Micron Document
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| SparkN0de-git | SparkN0de |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


Displaying Raw • Download


meshchatx/src/backend/http/routes/telephone.py master (977c7ad3) Text, 57.50 KB

T8b949e# SPDX-License-Identifier: 0BSD
T8b949e"""HTTP routes: telephone."""

Tff7b72from T7ee787__future__ Tff7b72import Te6edf3annotations


Tff7b72from T7ee787meshchatxT7ee787.T7ee787srcT7ee787.T7ee787backendT7ee787.T7ee787httpT7ee787.T7ee787meshchat_names Tff7b72import Tb4b4b4( T8b949e# noqa: F401
Te6edf3GeoValidationErrorTb4b4b4,
Te6edf3OutboundHttpBlockedErrorTb4b4b4,
Te6edf3OverlayExportErrorTb4b4b4,
Te6edf3OverlaySourceParseErrorTb4b4b4,
Te6edf3PluginSecurityErrorTb4b4b4,
Te6edf3AsyncUtilsTb4b4b4,
Te6edf3InterfaceConfigParserTb4b4b4,
Te6edf3InterfaceDiscoveryTb4b4b4,
Te6edf3InterfaceEditorTb4b4b4,
Te6edf3LOGIN_PATHTb4b4b4,
Te6edf3LXMFTb4b4b4,
Te6edf3LxmfAudioFieldTb4b4b4,
Te6edf3LxmfFileAttachmentTb4b4b4,
Te6edf3LxmfFileAttachmentsFieldTb4b4b4,
Te6edf3LxmfImageFieldTb4b4b4,
Te6edf3MAX_EXPORT_TILESTb4b4b4,
Te6edf3MarkdownRendererTb4b4b4,
Te6edf3NomadnetFileDownloaderTb4b4b4,
Te6edf3NomadnetPageDownloaderTb4b4b4,
Te6edf3RNProbeHandlerTb4b4b4,
Te6edf3RNSTb4b4b4,
Te6edf3ReticulumMeshChatTb4b4b4,
Te6edf3SETUP_PATHTb4b4b4,
Te6edf3TRANSPARENT_TILETb4b4b4,
Te6edf3TelemeterTb4b4b4,
Te6edf3UTCTb4b4b4,
Te6edf3WSMsgTypeTb4b4b4,
Te6edf3_is_chaquopy_androidTb4b4b4,
Te6edf3_is_loopback_bind_hostTb4b4b4,
Te6edf3_request_client_ipTb4b4b4,
Te6edf3aiohttpTb4b4b4,
Te6edf3app_versionTb4b4b4,
Te6edf3assert_migration_context_pathsTb4b4b4,
Te6edf3asyncioTb4b4b4,
Te6edf3base64Tb4b4b4,
Te6edf3bcryptTb4b4b4,
Te6edf3binasciiTb4b4b4,
Te6edf3build_blocklist_export_documentTb4b4b4,
Te6edf3build_export_documentTb4b4b4,
Te6edf3build_messages_export_bundleTb4b4b4,
Te6edf3cache_statsTb4b4b4,
Te6edf3cancel_inbound_deliveriesTb4b4b4,
Te6edf3castTb4b4b4,
Te6edf3compute_lxmf_conversation_unread_from_latest_rowTb4b4b4,
Te6edf3configparserTb4b4b4,
Te6edf3contextlibTb4b4b4,
Te6edf3convert_db_favourite_to_dictTb4b4b4,
Te6edf3convert_db_lxmf_message_to_dictTb4b4b4,
Te6edf3convert_lxmf_message_to_dictTb4b4b4,
Te6edf3convert_nomadnet_field_data_to_mapTb4b4b4,
Te6edf3convert_nomadnet_string_data_to_mapTb4b4b4,
Te6edf3convert_propagation_node_state_to_stringTb4b4b4,
Te6edf3copyTb4b4b4,
Te6edf3datetimeTb4b4b4,
Te6edf3describe_port_conflictTb4b4b4,
Te6edf3detect_image_format_from_magicTb4b4b4,
Te6edf3ensure_outbound_http_allowedTb4b4b4,
Te6edf3ensure_session_csrf_tokenTb4b4b4,
Te6edf3filter_announced_dicts_by_search_queryTb4b4b4,
Te6edf3fresh_storage_at_targetTb4b4b4,
Te6edf3get_cached_active_linkTb4b4b4,
Te6edf3get_file_pathTb4b4b4,
Te6edf3get_sessionTb4b4b4,
Te6edf3get_trusted_proxy_cidrsTb4b4b4,
Te6edf3gif_utilsTb4b4b4,
Te6edf3i2p_supportTb4b4b4,
Te6edf3import_messages_export_bundleTb4b4b4,
Te6edf3ioTb4b4b4,
Te6edf3is_mbtiles_filenameTb4b4b4,
Te6edf3is_path_within_dirTb4b4b4,
Te6edf3is_port_in_useTb4b4b4,
Te6edf3is_user_facing_lxmf_payloadTb4b4b4,
Te6edf3jsonTb4b4b4,
Te6edf3list_host_network_interfacesTb4b4b4,
Te6edf3list_inbound_deliveriesTb4b4b4,
Te6edf3list_portsTb4b4b4,
Te6edf3load_app_security_settingsTb4b4b4,
Te6edf3loggerTb4b4b4,
Te6edf3loggingTb4b4b4,
Te6edf3lxmf_sidebar_preview_for_conversation_latest_rowTb4b4b4,
Te6edf3memory_log_handlerTb4b4b4,
Te6edf3message_fields_have_attachmentsTb4b4b4,
Te6edf3migrate_legacy_to_targetTb4b4b4,
Te6edf3mime_for_image_typeTb4b4b4,
Te6edf3normalize_identity_storage_hashTb4b4b4,
Te6edf3normalize_lxmf_sieve_filtersTb4b4b4,
Te6edf3normalize_message_blocklistTb4b4b4,
Te6edf3osTb4b4b4,
Te6edf3parse_bool_query_paramTb4b4b4,
Te6edf3parse_import_documentTb4b4b4,
Te6edf3parse_lxmf_display_nameTb4b4b4,
Te6edf3parse_lxmf_propagation_node_app_dataTb4b4b4,
Te6edf3parse_lxmf_sieve_filters_jsonTb4b4b4,
Te6edf3parse_lxmf_stamp_costTb4b4b4,
Te6edf3parse_message_blocklist_jsonTb4b4b4,
Te6edf3parse_nomadnetwork_node_display_nameTb4b4b4,
Te6edf3platformTb4b4b4,
Te6edf3privacy_mode_enabledTb4b4b4,
Te6edf3psutilTb4b4b4,
Te6edf3purge_messages_before_cutoffTb4b4b4,
Te6edf3reTb4b4b4,
Te6edf3resolve_message_age_cutoffTb4b4b4,
Te6edf3reticulum_pathfindingTb4b4b4,
Te6edf3rotate_session_csrf_tokenTb4b4b4,
Te6edf3rrc_protocolTb4b4b4,
Te6edf3safe_path_under_dirTb4b4b4,
Te6edf3sanitize_sticker_emojiTb4b4b4,
Te6edf3sanitize_sticker_nameTb4b4b4,
Te6edf3sanitize_websocket_config_updateTb4b4b4,
Te6edf3save_app_security_settingsTb4b4b4,
Te6edf3secretsTb4b4b4,
Te6edf3shutilTb4b4b4,
Te6edf3sqlite3Tb4b4b4,
Te6edf3sticker_pack_utilsTb4b4b4,
Te6edf3sysTb4b4b4,
Te6edf3tempfileTb4b4b4,
Te6edf3threadingTb4b4b4,
Te6edf3timeTb4b4b4,
Te6edf3tracebackTb4b4b4,
Te6edf3user_agent_hashTb4b4b4,
Te6edf3validate_export_documentTb4b4b4,
Te6edf3webTb4b4b4,
Te6edf3websocket_type_requires_authTb4b4b4,
Te6edf3zipfileTb4b4b4,
Tb4b4b4)


Tff7b72async Tff7b72def Td2a8fffirst_multipart_file_fieldTb4b4b4(Te6edf3readerTb4b4b4, Te6edf3field_nameTff7b72=Ta5d6ff"Ta5d6fffileTa5d6ff"Tb4b4b4)Tb4b4b4:
T8b949e"""Return the first multipart part named field_name, or the first with a filename."""
Tff7b72while Tff7b72TrueTb4b4b4:
Te6edf3field Tff7b72= Tff7b72await Te6edf3readerTff7b72.Td2a8ffnextTb4b4b4(Tb4b4b4)
Tff7b72if Te6edf3field Tff7b72is Tff7b72NoneTb4b4b4:
Tff7b72return Tff7b72None
Te6edf3name Tff7b72= Te6edf3fieldTff7b72.Td2a8ffname Tff7b72or Ta5d6ff"Ta5d6ff"
Tff7b72if Te6edf3name Tff7b72== Te6edf3field_name Tff7b72or Te6edf3fieldTff7b72.Td2a8fffilenameTb4b4b4:
Tff7b72return Te6edf3field
Tff7b72with Te6edf3contextlibTff7b72.Td2a8ffsuppressTb4b4b4(Tf85149ExceptionTb4b4b4)Tb4b4b4:
Tff7b72await Te6edf3fieldTff7b72.Td2a8ffreadTb4b4b4(Tb4b4b4)


Tff7b72def Td2a8ffregister_telephone_routesTb4b4b4(Te6edf3routesTb4b4b4, Te6edf3appTb4b4b4)Tb4b4b4:

T8b949e# serve telephone status
Tf0883e@routesTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/telephone/statusTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8fftelephone_statusTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
T8b949e# make sure telephone is enabled
Tff7b72if Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8fftelephone Tff7b72is Tff7b72NoneTb4b4b4:
Te6edf3missed_calls_unread_count Tff7b72= T79c0ff0
Tff7b72if Te6edf3appTff7b72.Td2a8ffdatabase Tff7b72is Tff7b72not Tff7b72NoneTb4b4b4:
Tff7b72with Te6edf3contextlibTff7b72.Td2a8ffsuppressTb4b4b4(Tf85149ExceptionTb4b4b4)Tb4b4b4:
Te6edf3missed_calls_unread_count Tff7b72= Tb4b4b4(
Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8ffmiscTff7b72.Td2a8ffget_unread_notification_count_by_typeTb4b4b4(
Ta5d6ff"Ta5d6fftelephone_missed_callTa5d6ff"Tb4b4b4,
Tb4b4b4)
Tb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffenabledTa5d6ff"Tb4b4b4: Tff7b72FalseTb4b4b4,
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffTelephone is disabledTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffmissed_calls_unread_countTa5d6ff"Tb4b4b4: Te6edf3missed_calls_unread_countTb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)

T8b949e# get active call info
Te6edf3active_call Tff7b72= Tff7b72None
Te6edf3telephone_active_call Tff7b72= Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8fftelephoneTff7b72.Td2a8ffactive_call
Tff7b72if Te6edf3telephone_active_call Tff7b72is Tff7b72not Tff7b72NoneTb4b4b4:
T8b949e# Filter ringing inbound calls that policy must not surface
Te6edf3is_ringing Tff7b72= Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8fftelephoneTff7b72.Td2a8ffcall_status Tff7b72== T79c0ff4
Tff7b72if Te6edf3telephone_active_callTff7b72.Td2a8ffis_incoming Tff7b72and Te6edf3is_ringingTb4b4b4:
Te6edf3remote_identity Tff7b72= Te6edf3telephone_active_callTff7b72.Td2a8ffget_remote_identityTb4b4b4(Tb4b4b4)
Te6edf3caller_hash Tff7b72= Te6edf3remote_identityTff7b72.Td2a8ffhashTff7b72.Td2a8ffhexTb4b4b4(Tb4b4b4) Tff7b72if Te6edf3remote_identity Tff7b72else Tff7b72None
Tff7b72if Tff7b72not Te6edf3caller_hash Tff7b72or Te6edf3appTff7b72.Td2a8ffincoming_call_is_policy_filteredTb4b4b4(
Te6edf3caller_hashTb4b4b4,
Tb4b4b4)Tb4b4b4:
Te6edf3telephone_active_call Tff7b72= Tff7b72None

Tff7b72if Te6edf3telephone_active_call Tff7b72is Tff7b72not Tff7b72NoneTb4b4b4:
Te6edf3remote_identity Tff7b72= Te6edf3telephone_active_callTff7b72.Td2a8ffget_remote_identityTb4b4b4(Tb4b4b4)
Tff7b72if Te6edf3remote_identity Tff7b72is Tff7b72NoneTb4b4b4:
Te6edf3telephone_active_call Tff7b72= Tff7b72None

Tff7b72if Te6edf3telephone_active_call Tff7b72is Tff7b72not Tff7b72NoneTb4b4b4:
T8b949e# remote_identity is already fetched and checked for None above
Te6edf3remote_hash Tff7b72= Te6edf3remote_identityTff7b72.Td2a8ffhashTff7b72.Td2a8ffhexTb4b4b4(Tb4b4b4)
Te6edf3remote_destination_hash Tff7b72= Te6edf3RNSTff7b72.Td2a8ffDestinationTff7b72.Td2a8ffhashTb4b4b4(
Te6edf3remote_identityTb4b4b4,
Ta5d6ff"Ta5d6fflxmfTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffdeliveryTa5d6ff"Tb4b4b4,
Tb4b4b4)Tff7b72.Td2a8ffhexTb4b4b4(Tb4b4b4)
Te6edf3remote_telephony_hash Tff7b72= Te6edf3appTff7b72.Td2a8ffget_lxst_telephony_hash_for_identity_hashTb4b4b4(
Te6edf3remote_hashTb4b4b4,
Tb4b4b4)
Te6edf3remote_name Tff7b72= Tff7b72None
Tff7b72if Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8ffget_name_for_identity_hashTb4b4b4:
Te6edf3remote_name Tff7b72= Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8ffget_name_for_identity_hashTb4b4b4(
Te6edf3remote_hashTb4b4b4,
Tb4b4b4)

T8b949e# get lxmf destination hash to look up icon
Te6edf3lxmf_destination_hash Tff7b72= Te6edf3RNSTff7b72.Td2a8ffDestinationTff7b72.Td2a8ffhashTb4b4b4(
Te6edf3remote_identityTb4b4b4,
Ta5d6ff"Ta5d6fflxmfTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffdeliveryTa5d6ff"Tb4b4b4,
Tb4b4b4)Tff7b72.Td2a8ffhexTb4b4b4(Tb4b4b4)

Te6edf3remote_icon Tff7b72= Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8ffmiscTff7b72.Td2a8ffget_user_iconTb4b4b4(Te6edf3lxmf_destination_hashTb4b4b4)

T8b949e# Check if contact and get custom image
Te6edf3contact Tff7b72= Te6edf3appTff7b72.Td2a8ff_resolve_contact_for_hashTb4b4b4(Te6edf3remote_hashTb4b4b4)
Te6edf3custom_image Tff7b72= Te6edf3contactTb4b4b4[Ta5d6ff"Ta5d6ffcustom_imageTa5d6ff"Tb4b4b4] Tff7b72if Te6edf3contact Tff7b72else Tff7b72None

Te6edf3active_call Tff7b72= Tb4b4b4{
Ta5d6ff"Ta5d6ffhashTa5d6ff"Tb4b4b4: Te6edf3telephone_active_callTff7b72.Td2a8ffhashTff7b72.Td2a8ffhexTb4b4b4(Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffremote_identity_hashTa5d6ff"Tb4b4b4: Te6edf3remote_hashTb4b4b4,
Ta5d6ff"Ta5d6ffremote_destination_hashTa5d6ff"Tb4b4b4: Te6edf3remote_destination_hashTb4b4b4,
Ta5d6ff"Ta5d6ffremote_identity_nameTa5d6ff"Tb4b4b4: Te6edf3remote_nameTb4b4b4,
Ta5d6ff"Ta5d6ffremote_iconTa5d6ff"Tb4b4b4: Tffa657dictTb4b4b4(Te6edf3remote_iconTb4b4b4) Tff7b72if Te6edf3remote_icon Tff7b72else Tff7b72NoneTb4b4b4,
Ta5d6ff"Ta5d6ffcustom_imageTa5d6ff"Tb4b4b4: Te6edf3custom_imageTb4b4b4,
Ta5d6ff"Ta5d6ffis_incomingTa5d6ff"Tb4b4b4: Te6edf3telephone_active_callTff7b72.Td2a8ffis_incomingTb4b4b4,
Ta5d6ff"Ta5d6ffstatusTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8fftelephoneTff7b72.Td2a8ffcall_statusTb4b4b4,
Ta5d6ff"Ta5d6ffremote_telephony_hashTa5d6ff"Tb4b4b4: Te6edf3remote_telephony_hashTb4b4b4,
Ta5d6ff"Ta5d6ffaudio_profile_idTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8fftelephoneTff7b72.Td2a8fftransmit_codecTff7b72.Td2a8ffprofile
Tff7b72if Tffa657hasattrTb4b4b4(
Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8fftelephoneTff7b72.Td2a8fftransmit_codecTb4b4b4,
Ta5d6ff"Ta5d6ffprofileTa5d6ff"Tb4b4b4,
Tb4b4b4)
Tff7b72else Tff7b72NoneTb4b4b4,
Ta5d6ff"Ta5d6ffcall_mode_idTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8ffget_active_mode_idTb4b4b4(Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffis_half_duplexTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8ffis_half_duplexTb4b4b4(Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffis_ptt_activeTa5d6ff"Tb4b4b4: Tffa657boolTb4b4b4(Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8ffptt_activeTb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffis_transmit_squelchedTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8ffis_transmit_squelchedTb4b4b4(Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffis_mic_mutedTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8fftransmit_mutedTb4b4b4,
Ta5d6ff"Ta5d6ffis_speaker_mutedTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8ffreceive_mutedTb4b4b4,
Ta5d6ff"Ta5d6ffis_recordingTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8ffis_recordingTb4b4b4,
Ta5d6ff"Ta5d6ffis_voicemailTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8ffvoicemail_managerTff7b72.Td2a8ffis_recordingTb4b4b4,
Ta5d6ff"Ta5d6ffcall_start_timeTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8ffcall_start_timeTb4b4b4,
Ta5d6ff"Ta5d6ffis_contactTa5d6ff"Tb4b4b4: Te6edf3contact Tff7b72is Tff7b72not Tff7b72NoneTb4b4b4,
Ta5d6ff"Ta5d6fftx_bytesTa5d6ff"Tb4b4b4: T79c0ff0Tb4b4b4,
Ta5d6ff"Ta5d6ffrx_bytesTa5d6ff"Tb4b4b4: T79c0ff0Tb4b4b4,
Ta5d6ff"Ta5d6fftx_packetsTa5d6ff"Tb4b4b4: T79c0ff0Tb4b4b4,
Ta5d6ff"Ta5d6ffrx_packetsTa5d6ff"Tb4b4b4: T79c0ff0Tb4b4b4,
Ta5d6ff"Ta5d6fftx_bpsTa5d6ff"Tb4b4b4: T79c0ff0Tb4b4b4,
Ta5d6ff"Ta5d6ffrx_bpsTa5d6ff"Tb4b4b4: T79c0ff0Tb4b4b4,
Ta5d6ff"Ta5d6ffpath_hopsTa5d6ff"Tb4b4b4: Tff7b72NoneTb4b4b4,
Ta5d6ff"Ta5d6ffpath_interfaceTa5d6ff"Tb4b4b4: Tff7b72NoneTb4b4b4,
Tb4b4b4}
Tff7b72from T7ee787meshchatxT7ee787.T7ee787srcT7ee787.T7ee787backend Tff7b72import Te6edf3lxst_profiles_compat Tff7b72as Te6edf3lxst_modes

Te6edf3mode_id Tff7b72= Te6edf3active_callTb4b4b4[Ta5d6ff"Ta5d6ffcall_mode_idTa5d6ff"Tb4b4b4]
Tff7b72with Te6edf3contextlibTff7b72.Td2a8ffsuppressTb4b4b4(Tf85149ExceptionTb4b4b4)Tb4b4b4:
Te6edf3active_callTb4b4b4[Ta5d6ff"Ta5d6ffcall_mode_nameTa5d6ff"Tb4b4b4] Tff7b72= Te6edf3lxst_modesTff7b72.Td2a8ffmode_nameTb4b4b4(Te6edf3mode_idTb4b4b4)
Te6edf3active_callTb4b4b4[Ta5d6ff"Ta5d6ffcall_mode_abbrevTa5d6ff"Tb4b4b4] Tff7b72= Te6edf3lxst_modesTff7b72.Td2a8ffmode_abbreviationTb4b4b4(Te6edf3mode_idTb4b4b4)
Te6edf3link Tff7b72= Tffa657getattrTb4b4b4(Te6edf3appTff7b72.Td2a8fftelephone_managerTb4b4b4, Ta5d6ff"Ta5d6ffcall_statsTa5d6ff"Tb4b4b4, Tb4b4b4{Tb4b4b4}Tb4b4b4)Tff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fflinkTa5d6ff"Tb4b4b4)
Tff7b72if Te6edf3linkTb4b4b4:
Te6edf3active_callTb4b4b4[Ta5d6ff"Ta5d6fftx_bytesTa5d6ff"Tb4b4b4] Tff7b72= Tffa657getattrTb4b4b4(Te6edf3linkTb4b4b4, Ta5d6ff"Ta5d6fftxbytesTa5d6ff"Tb4b4b4, T79c0ff0Tb4b4b4)
Te6edf3active_callTb4b4b4[Ta5d6ff"Ta5d6ffrx_bytesTa5d6ff"Tb4b4b4] Tff7b72= Tffa657getattrTb4b4b4(Te6edf3linkTb4b4b4, Ta5d6ff"Ta5d6ffrxbytesTa5d6ff"Tb4b4b4, T79c0ff0Tb4b4b4)
Te6edf3active_callTb4b4b4[Ta5d6ff"Ta5d6fftx_packetsTa5d6ff"Tb4b4b4] Tff7b72= Tffa657getattrTb4b4b4(Te6edf3linkTb4b4b4, Ta5d6ff"Ta5d6fftxTa5d6ff"Tb4b4b4, T79c0ff0Tb4b4b4)
Te6edf3active_callTb4b4b4[Ta5d6ff"Ta5d6ffrx_packetsTa5d6ff"Tb4b4b4] Tff7b72= Tffa657getattrTb4b4b4(Te6edf3linkTb4b4b4, Ta5d6ff"Ta5d6ffrxTa5d6ff"Tb4b4b4, T79c0ff0Tb4b4b4)
Te6edf3started_at Tff7b72= Tffa657getattrTb4b4b4(Te6edf3appTff7b72.Td2a8fftelephone_managerTb4b4b4, Ta5d6ff"Ta5d6ffcall_statsTa5d6ff"Tb4b4b4, Tb4b4b4{Tb4b4b4}Tb4b4b4)Tff7b72.Td2a8ffgetTb4b4b4(
Ta5d6ff"Ta5d6ffstarted_atTa5d6ff"Tb4b4b4,
Tb4b4b4)
Tff7b72if Tff7b72not Te6edf3started_atTb4b4b4:
Te6edf3started_at Tff7b72= Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8ffcall_start_time
Te6edf3elapsed Tff7b72= Tb4b4b4(
Tffa657maxTb4b4b4(T79c0ff0.001Tb4b4b4, Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4) Tff7b72- Tffa657floatTb4b4b4(Te6edf3started_atTb4b4b4)Tb4b4b4) Tff7b72if Te6edf3started_at Tff7b72else T79c0ff0.0
Tb4b4b4)
Tff7b72if Te6edf3elapsed Tff7b72> T79c0ff0Tb4b4b4:
Te6edf3active_callTb4b4b4[Ta5d6ff"Ta5d6fftx_bpsTa5d6ff"Tb4b4b4] Tff7b72= Tffa657intTb4b4b4(
Tb4b4b4(Te6edf3active_callTb4b4b4[Ta5d6ff"Ta5d6fftx_bytesTa5d6ff"Tb4b4b4] Tff7b72* T79c0ff8Tb4b4b4) Tff7b72/ Te6edf3elapsedTb4b4b4,
Tb4b4b4)
Te6edf3active_callTb4b4b4[Ta5d6ff"Ta5d6ffrx_bpsTa5d6ff"Tb4b4b4] Tff7b72= Tffa657intTb4b4b4(
Tb4b4b4(Te6edf3active_callTb4b4b4[Ta5d6ff"Ta5d6ffrx_bytesTa5d6ff"Tb4b4b4] Tff7b72* T79c0ff8Tb4b4b4) Tff7b72/ Te6edf3elapsedTb4b4b4,
Tb4b4b4)
T8b949e# Best-effort direct link metadata fallback.
Tff7b72if Te6edf3active_callTb4b4b4[Ta5d6ff"Ta5d6ffpath_hopsTa5d6ff"Tb4b4b4] Tff7b72is Tff7b72NoneTb4b4b4:
Tff7b72for Te6edf3hop_attr Tff7b72in Tb4b4b4[Ta5d6ff"Ta5d6ffhopsTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffhop_countTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffpath_hopsTa5d6ff"Tb4b4b4]Tb4b4b4:
Te6edf3hops_val Tff7b72= Tffa657getattrTb4b4b4(Te6edf3linkTb4b4b4, Te6edf3hop_attrTb4b4b4, Tff7b72NoneTb4b4b4)
Tff7b72if Tffa657isinstanceTb4b4b4(Te6edf3hops_valTb4b4b4, Tffa657intTb4b4b4)Tb4b4b4:
Te6edf3active_callTb4b4b4[Ta5d6ff"Ta5d6ffpath_hopsTa5d6ff"Tb4b4b4] Tff7b72= Te6edf3hops_val
Tff7b72break
Tff7b72if Tff7b72not Te6edf3active_callTb4b4b4[Ta5d6ff"Ta5d6ffpath_interfaceTa5d6ff"Tb4b4b4]Tb4b4b4:
Tff7b72for Te6edf3iface_attr Tff7b72in Tb4b4b4[Ta5d6ff"Ta5d6ffattached_interfaceTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffinterfaceTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffifacTa5d6ff"Tb4b4b4]Tb4b4b4:
Te6edf3iface_val Tff7b72= Tffa657getattrTb4b4b4(Te6edf3linkTb4b4b4, Te6edf3iface_attrTb4b4b4, Tff7b72NoneTb4b4b4)
Tff7b72if Tffa657isinstanceTb4b4b4(Te6edf3iface_valTb4b4b4, Tffa657strTb4b4b4) Tff7b72and Te6edf3iface_valTff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4)Tb4b4b4:
Te6edf3active_callTb4b4b4[Ta5d6ff"Ta5d6ffpath_interfaceTa5d6ff"Tb4b4b4] Tff7b72= Te6edf3iface_valTff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4)
Tff7b72break
Te6edf3iface_name Tff7b72= Tb4b4b4(
Tffa657getattrTb4b4b4(Te6edf3iface_valTb4b4b4, Ta5d6ff"Ta5d6ffnameTa5d6ff"Tb4b4b4, Tff7b72NoneTb4b4b4) Tff7b72if Te6edf3iface_val Tff7b72else Tff7b72None
Tb4b4b4)
Tff7b72if Tffa657isinstanceTb4b4b4(Te6edf3iface_nameTb4b4b4, Tffa657strTb4b4b4) Tff7b72and Te6edf3iface_nameTff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4)Tb4b4b4:
Te6edf3active_callTb4b4b4[Ta5d6ff"Ta5d6ffpath_interfaceTa5d6ff"Tb4b4b4] Tff7b72= Te6edf3iface_nameTff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4)
Tff7b72break

T8b949e# Try multiple destination hashes. Depending on LXST state, the
T8b949e# active call hash is not always the route-resolvable destination.
Tff7b72for Te6edf3candidate_hex Tff7b72in Tb4b4b4[
Te6edf3remote_telephony_hashTb4b4b4,
Te6edf3remote_hashTb4b4b4,
Te6edf3active_callTb4b4b4[Ta5d6ff"Ta5d6ffhashTa5d6ff"Tb4b4b4]Tb4b4b4,
Te6edf3remote_destination_hashTb4b4b4,
Tb4b4b4]Tb4b4b4:
Tff7b72if Tff7b72not Te6edf3candidate_hexTb4b4b4:
Tff7b72continue
Tff7b72tryTb4b4b4:
Te6edf3candidate_hash Tff7b72= Tffa657bytesTff7b72.Td2a8fffromhexTb4b4b4(Te6edf3candidate_hexTb4b4b4)
Tff7b72except Tf85149ExceptionTb4b4b4:
Tff7b72continue
Tff7b72tryTb4b4b4:
Tff7b72if Tff7b72not Te6edf3RNSTff7b72.Td2a8ffTransportTff7b72.Td2a8ffhas_pathTb4b4b4(Te6edf3candidate_hashTb4b4b4)Tb4b4b4:
Tff7b72continue
Te6edf3active_callTb4b4b4[Ta5d6ff"Ta5d6ffpath_hopsTa5d6ff"Tb4b4b4] Tff7b72= Te6edf3RNSTff7b72.Td2a8ffTransportTff7b72.Td2a8ffhops_toTb4b4b4(Te6edf3candidate_hashTb4b4b4)
Tff7b72if Tffa657hasattrTb4b4b4(Te6edf3appTb4b4b4, Ta5d6ff"Ta5d6ffreticulumTa5d6ff"Tb4b4b4) Tff7b72and Te6edf3appTff7b72.Td2a8ffreticulumTb4b4b4:
Te6edf3active_callTb4b4b4[Ta5d6ff"Ta5d6ffpath_interfaceTa5d6ff"Tb4b4b4] Tff7b72= Tb4b4b4(
Te6edf3appTff7b72.Td2a8ffreticulumTff7b72.Td2a8ffget_next_hop_if_nameTb4b4b4(
Te6edf3candidate_hashTb4b4b4,
Tb4b4b4)
Tb4b4b4)
Tff7b72break
Tff7b72except Tf85149ExceptionTb4b4b4:
Tff7b72continue

Te6edf3initiation_target_hash Tff7b72= Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8ffinitiation_target_hash
Te6edf3initiation_target_name Tff7b72= Tff7b72None
Tff7b72if Te6edf3initiation_target_hashTb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3contact Tff7b72= Te6edf3appTff7b72.Td2a8ff_resolve_contact_for_hashTb4b4b4(Te6edf3initiation_target_hashTb4b4b4)
Tff7b72if Te6edf3contactTb4b4b4:
Te6edf3initiation_target_name Tff7b72= Te6edf3contactTb4b4b4[Ta5d6ff"Ta5d6ffnameTa5d6ff"Tb4b4b4]
Tff7b72except Tf85149ExceptionTb4b4b4:
Tff7b72pass

Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffenabledTa5d6ff"Tb4b4b4: Tff7b72TrueTb4b4b4,
Ta5d6ff"Ta5d6ffis_busyTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8fftelephoneTff7b72.Td2a8ffbusyTb4b4b4,
Ta5d6ff"Ta5d6ffcall_statusTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8fftelephoneTff7b72.Td2a8ffcall_statusTb4b4b4,
Ta5d6ff"Ta5d6ffactive_callTa5d6ff"Tb4b4b4: Te6edf3active_callTb4b4b4,
Ta5d6ff"Ta5d6ffis_mic_mutedTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8fftransmit_mutedTb4b4b4,
Ta5d6ff"Ta5d6ffis_speaker_mutedTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8ffreceive_mutedTb4b4b4,
Ta5d6ff"Ta5d6ffpreferred_call_mode_idTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8ffresolve_call_mode_idTb4b4b4(
Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8ffpreferred_mode_idTb4b4b4,
Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffmissed_calls_unread_countTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8ffmiscTff7b72.Td2a8ffget_unread_notification_count_by_typeTb4b4b4(
Ta5d6ff"Ta5d6fftelephone_missed_callTa5d6ff"Tb4b4b4,
Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffvoicemailTa5d6ff"Tb4b4b4: Tb4b4b4{
Ta5d6ff"Ta5d6ffis_recordingTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8ffvoicemail_managerTff7b72.Td2a8ffis_recordingTb4b4b4,
Ta5d6ff"Ta5d6ffunread_countTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8ffvoicemailsTff7b72.Td2a8ffget_unread_countTb4b4b4(Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6fflatest_idTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8ffvoicemailsTff7b72.Td2a8ffget_latest_voicemail_idTb4b4b4(Tb4b4b4)Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Ta5d6ff"Ta5d6ffinitiation_statusTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8ffinitiation_statusTb4b4b4,
Ta5d6ff"Ta5d6ffinitiation_target_hashTa5d6ff"Tb4b4b4: Te6edf3initiation_target_hashTb4b4b4,
Ta5d6ff"Ta5d6ffinitiation_target_nameTa5d6ff"Tb4b4b4: Te6edf3initiation_target_nameTb4b4b4,
T8b949e# Silence web audio during voicemail
Ta5d6ff"Ta5d6ffweb_audioTa5d6ff"Tb4b4b4: Tb4b4b4{
Ta5d6ff"Ta5d6ffenabledTa5d6ff"Tb4b4b4: Tb4b4b4(
Tffa657getattrTb4b4b4(
Te6edf3appTff7b72.Td2a8ffconfigTff7b72.Td2a8fftelephone_web_audio_enabledTb4b4b4,
Ta5d6ff"Ta5d6ffgetTa5d6ff"Tb4b4b4,
Tff7b72lambdaTb4b4b4: Tff7b72FalseTb4b4b4,
Tb4b4b4)Tb4b4b4(Tb4b4b4)
Tff7b72or Te6edf3appTff7b72.Td2a8ffweb_audio_requiredTb4b4b4(Tb4b4b4)
Tb4b4b4)
Tff7b72and Tff7b72not Tffa657boolTb4b4b4(
Tffa657getattrTb4b4b4(Te6edf3appTff7b72.Td2a8ffvoicemail_managerTb4b4b4, Ta5d6ff"Ta5d6ffis_recordingTa5d6ff"Tb4b4b4, Tff7b72FalseTb4b4b4)Tb4b4b4,
Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffrequiredTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8ffweb_audio_requiredTb4b4b4(Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffallow_fallbackTa5d6ff"Tb4b4b4: Tffa657getattrTb4b4b4(
Te6edf3appTff7b72.Td2a8ffconfigTff7b72.Td2a8fftelephone_web_audio_allow_fallbackTb4b4b4,
Ta5d6ff"Ta5d6ffgetTa5d6ff"Tb4b4b4,
Tff7b72lambdaTb4b4b4: Tff7b72TrueTb4b4b4,
Tb4b4b4)Tb4b4b4(Tb4b4b4)
Tff7b72and Tff7b72not Te6edf3appTff7b72.Td2a8ffweb_audio_requiredTb4b4b4(Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffhas_clientTa5d6ff"Tb4b4b4: Tffa657boolTb4b4b4(
Tffa657getattrTb4b4b4(Te6edf3appTff7b72.Td2a8ffweb_audio_bridgeTb4b4b4, Ta5d6ff"Ta5d6ffclientsTa5d6ff"Tb4b4b4, Tb4b4b4[Tb4b4b4]Tb4b4b4)Tb4b4b4,
Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffframe_msTa5d6ff"Tb4b4b4: Tffa657getattrTb4b4b4(
Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8fftelephoneTb4b4b4,
Ta5d6ff"Ta5d6fftarget_frame_time_msTa5d6ff"Tb4b4b4,
Tff7b72NoneTb4b4b4,
Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffdiagnosticsTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8ffweb_audio_bridgeTff7b72.Td2a8ffget_diagnosticsTb4b4b4(Tb4b4b4)
Tff7b72if Tffa657hasattrTb4b4b4(Te6edf3appTff7b72.Td2a8ffweb_audio_bridgeTb4b4b4, Ta5d6ff"Ta5d6ffget_diagnosticsTa5d6ff"Tb4b4b4)
Tff7b72else Tff7b72NoneTb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)

Tf0883e@routesTff7b72.Td2a8ffpostTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/telephone/missed-calls/mark-viewedTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8fftelephone_missed_calls_mark_viewedTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Te6edf3not_ready Tff7b72= Te6edf3appTff7b72.Td2a8ff_require_identity_context_readyTb4b4b4(Tb4b4b4)
Tff7b72if Te6edf3not_ready Tff7b72is Tff7b72not Tff7b72NoneTb4b4b4:
Tff7b72return Te6edf3not_ready
Tff7b72await Te6edf3asyncioTff7b72.Td2a8ffto_threadTb4b4b4(
Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8ffmiscTff7b72.Td2a8ffdismiss_unviewed_notificationsTb4b4b4,
Ta5d6ff"Ta5d6fftelephone_missed_callTa5d6ff"Tb4b4b4,
Tb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffokTa5d6ff"Tb4b4b4}Tb4b4b4)

T8b949e# answer incoming telephone call

T8b949e# answer incoming telephone call
Tf0883e@routesTff7b72.Td2a8ffpostTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/telephone/answerTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8fftelephone_answerTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
T8b949e# get incoming caller identity
Te6edf3active_call Tff7b72= Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8fftelephoneTff7b72.Td2a8ffactive_call
Tff7b72if Tff7b72not Te6edf3active_callTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffNo active callTa5d6ff"Tb4b4b4}Tb4b4b4, Te6edf3statusTff7b72=T79c0ff404Tb4b4b4)

Te6edf3caller_identity Tff7b72= Te6edf3active_callTff7b72.Td2a8ffget_remote_identityTb4b4b4(Tb4b4b4)
Tff7b72if Tff7b72not Te6edf3caller_identityTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffCaller identity not foundTa5d6ff"Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff404Tb4b4b4,
Tb4b4b4)

Te6edf3caller_hash Tff7b72= Te6edf3caller_identityTff7b72.Td2a8ffhashTff7b72.Td2a8ffhexTb4b4b4(Tb4b4b4)
Tff7b72if Te6edf3appTff7b72.Td2a8ffis_destination_blockedTb4b4b4(Te6edf3caller_hashTb4b4b4)Tb4b4b4:
Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8ffrequest_hangupTb4b4b4(Tb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffCaller is banishedTa5d6ff"Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff403Tb4b4b4,
Tb4b4b4)

T8b949e# answer call
Tff7b72await Te6edf3asyncioTff7b72.Td2a8ffto_threadTb4b4b4(
Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8fftelephoneTff7b72.Td2a8ffanswerTb4b4b4,
Te6edf3caller_identityTb4b4b4,
Tb4b4b4)

Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffAnswering call...Ta5d6ff"Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)

T8b949e# hangup active telephone call

T8b949e# hangup active telephone call
Tf0883e@routesTff7b72.Td2a8ffpostTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/telephone/hangupTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8fftelephone_hangupTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8ffrequest_hangupTb4b4b4(Tb4b4b4)

Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffHanging up call...Ta5d6ff"Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)

T8b949e# send active call to voicemail

T8b949e# send active call to voicemail
Tf0883e@routesTff7b72.Td2a8ffpostTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/telephone/send-to-voicemailTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8fftelephone_send_to_voicemailTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Te6edf3active_call Tff7b72= Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8fftelephoneTff7b72.Td2a8ffactive_call
Tff7b72if Tff7b72not Te6edf3active_callTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffNo active callTa5d6ff"Tb4b4b4}Tb4b4b4, Te6edf3statusTff7b72=T79c0ff404Tb4b4b4)

Te6edf3caller_identity Tff7b72= Te6edf3active_callTff7b72.Td2a8ffget_remote_identityTb4b4b4(Tb4b4b4)
Tff7b72if Tff7b72not Te6edf3caller_identityTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffNo remote identityTa5d6ff"Tb4b4b4}Tb4b4b4, Te6edf3statusTff7b72=T79c0ff400Tb4b4b4)

Tff7b72if Te6edf3appTff7b72.Td2a8ffis_destination_blockedTb4b4b4(Te6edf3caller_identityTff7b72.Td2a8ffhashTff7b72.Td2a8ffhexTb4b4b4(Tb4b4b4)Tb4b4b4)Tb4b4b4:
Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8ffrequest_hangupTb4b4b4(Tb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffCaller is banishedTa5d6ff"Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff403Tb4b4b4,
Tb4b4b4)

T8b949e# trigger voicemail session
Tff7b72await Te6edf3asyncioTff7b72.Td2a8ffto_threadTb4b4b4(
Te6edf3appTff7b72.Td2a8ffvoicemail_managerTff7b72.Td2a8ffstart_voicemail_sessionTb4b4b4,
Te6edf3caller_identityTb4b4b4,
Tb4b4b4)

Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffCall sent to voicemailTa5d6ff"Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)

T8b949e# mute/unmute transmit

T8b949e# mute/unmute transmit
Tf0883e@routesTff7b72.Td2a8ffpostTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/telephone/mute-transmitTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8fftelephone_mute_transmitTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Tff7b72await Te6edf3asyncioTff7b72.Td2a8ffto_threadTb4b4b4(Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8ffmute_transmitTb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffMicrophone mutedTa5d6ff"Tb4b4b4}Tb4b4b4)

Tf0883e@routesTff7b72.Td2a8ffpostTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/telephone/unmute-transmitTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8fftelephone_unmute_transmitTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Tff7b72await Te6edf3asyncioTff7b72.Td2a8ffto_threadTb4b4b4(Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8ffunmute_transmitTb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffMicrophone unmutedTa5d6ff"Tb4b4b4}Tb4b4b4)

T8b949e# mute/unmute receive

T8b949e# mute/unmute receive
Tf0883e@routesTff7b72.Td2a8ffpostTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/telephone/mute-receiveTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8fftelephone_mute_receiveTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Tff7b72await Te6edf3asyncioTff7b72.Td2a8ffto_threadTb4b4b4(Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8ffmute_receiveTb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffSpeaker mutedTa5d6ff"Tb4b4b4}Tb4b4b4)

Tf0883e@routesTff7b72.Td2a8ffpostTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/telephone/unmute-receiveTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8fftelephone_unmute_receiveTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Tff7b72await Te6edf3asyncioTff7b72.Td2a8ffto_threadTb4b4b4(Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8ffunmute_receiveTb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffSpeaker unmutedTa5d6ff"Tb4b4b4}Tb4b4b4)

Tf0883e@routesTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/telephone/call-modesTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8fftelephone_call_modesTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Tff7b72from T7ee787meshchatxT7ee787.T7ee787srcT7ee787.T7ee787backend Tff7b72import Te6edf3lxst_profiles_compat Tff7b72as Te6edf3lxst_modes

Te6edf3half Tff7b72= Te6edf3lxst_modesTff7b72.Td2a8ffmode_half_duplexTb4b4b4(Tb4b4b4)
Te6edf3modes Tff7b72= Tb4b4b4[
Tb4b4b4{
Ta5d6ff"Ta5d6ffidTa5d6ff"Tb4b4b4: Te6edf3mode_idTb4b4b4,
Ta5d6ff"Ta5d6ffnameTa5d6ff"Tb4b4b4: Te6edf3lxst_modesTff7b72.Td2a8ffmode_nameTb4b4b4(Te6edf3mode_idTb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffabbrevTa5d6ff"Tb4b4b4: Te6edf3lxst_modesTff7b72.Td2a8ffmode_abbreviationTb4b4b4(Te6edf3mode_idTb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffis_half_duplexTa5d6ff"Tb4b4b4: Te6edf3mode_id Tff7b72== Te6edf3halfTb4b4b4,
Tb4b4b4}
Tff7b72for Te6edf3mode_id Tff7b72in Te6edf3lxst_modesTff7b72.Td2a8ffavailable_modesTb4b4b4(Tb4b4b4)
Tb4b4b4]
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffdefault_call_mode_idTa5d6ff"Tb4b4b4: Te6edf3lxst_modesTff7b72.Td2a8ffdefault_modeTb4b4b4(Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffcall_modesTa5d6ff"Tb4b4b4: Te6edf3modesTb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)

Tf0883e@routesTff7b72.Td2a8ffpostTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/telephone/switch-call-mode/Tffd700{mode_id}Ta5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8fftelephone_switch_call_modeTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Te6edf3mode_id Tff7b72= Te6edf3requestTff7b72.Td2a8ffmatch_infoTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffmode_idTa5d6ff"Tb4b4b4)
Tff7b72tryTb4b4b4:
Tff7b72if Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8fftelephone Tff7b72is Tff7b72NoneTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffTelephone not initializedTa5d6ff"Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff400Tb4b4b4,
Tb4b4b4)
Te6edf3resolved Tff7b72= Tff7b72await Te6edf3asyncioTff7b72.Td2a8ffto_threadTb4b4b4(
Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8ffapply_preferred_modeTb4b4b4,
Tffa657intTb4b4b4(Te6edf3mode_idTb4b4b4)Tb4b4b4,
Tb4b4b4)
Te6edf3appTff7b72.Td2a8ffconfigTff7b72.Td2a8fftelephone_call_mode_idTff7b72.Td2a8ffsetTb4b4b4(Te6edf3resolvedTb4b4b4)
Tff7b72from T7ee787meshchatxT7ee787.T7ee787srcT7ee787.T7ee787backend Tff7b72import Te6edf3lxst_profiles_compat Tff7b72as Te6edf3lxst_modes

Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6fffTa5d6ff"Ta5d6ffSwitched to mode Tffd700{Te6edf3resolvedTffd700}Ta5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffmode_idTa5d6ff"Tb4b4b4: Te6edf3resolvedTb4b4b4,
Ta5d6ff"Ta5d6ffmode_nameTa5d6ff"Tb4b4b4: Te6edf3lxst_modesTff7b72.Td2a8ffmode_nameTb4b4b4(Te6edf3resolvedTb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffis_half_duplexTa5d6ff"Tb4b4b4: Te6edf3resolved Tff7b72== Te6edf3lxst_modesTff7b72.Td2a8ffmode_half_duplexTb4b4b4(Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffis_ptt_activeTa5d6ff"Tb4b4b4: Tffa657boolTb4b4b4(Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8ffptt_activeTb4b4b4)Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4}Tb4b4b4, Te6edf3statusTff7b72=T79c0ff500Tb4b4b4)

Tf0883e@routesTff7b72.Td2a8ffpostTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/telephone/pttTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8fftelephone_pttTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Tff7b72if Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8fftelephone Tff7b72is Tff7b72NoneTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffTelephone not initializedTa5d6ff"Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff400Tb4b4b4,
Tb4b4b4)
Tff7b72tryTb4b4b4:
Te6edf3data Tff7b72= Tff7b72await Te6edf3requestTff7b72.Td2a8ffjsonTb4b4b4(Tb4b4b4)
Tff7b72except Tf85149ExceptionTb4b4b4:
Te6edf3data Tff7b72= Tb4b4b4{Tb4b4b4}
Te6edf3active Tff7b72= Tffa657boolTb4b4b4(Te6edf3dataTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffactiveTa5d6ff"Tb4b4b4, Tff7b72FalseTb4b4b4)Tb4b4b4) Tff7b72if Tffa657isinstanceTb4b4b4(Te6edf3dataTb4b4b4, Tffa657dictTb4b4b4) Tff7b72else Tff7b72False
Te6edf3ok Tff7b72= Tff7b72await Te6edf3asyncioTff7b72.Td2a8ffto_threadTb4b4b4(Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8ffset_ptt_activeTb4b4b4, Te6edf3activeTb4b4b4)
Tff7b72if Tff7b72not Te6edf3ok Tff7b72and Te6edf3activeTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffPTT requires an established half-duplex callTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffis_ptt_activeTa5d6ff"Tb4b4b4: Tffa657boolTb4b4b4(Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8ffptt_activeTb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffis_half_duplexTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8ffis_half_duplexTb4b4b4(Tb4b4b4)Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff400Tb4b4b4,
Tb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffokTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffis_ptt_activeTa5d6ff"Tb4b4b4: Tffa657boolTb4b4b4(Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8ffptt_activeTb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffis_half_duplexTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8ffis_half_duplexTb4b4b4(Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffis_transmit_squelchedTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8ffis_transmit_squelchedTb4b4b4(Tb4b4b4)Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)

T8b949e# get call history

T8b949e# get call history
Tf0883e@routesTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/telephone/historyTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8fftelephone_historyTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Te6edf3limit Tff7b72= Tffa657intTb4b4b4(Te6edf3requestTff7b72.Td2a8ffqueryTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fflimitTa5d6ff"Tb4b4b4, T79c0ff10Tb4b4b4)Tb4b4b4)
Te6edf3offset Tff7b72= Tffa657intTb4b4b4(Te6edf3requestTff7b72.Td2a8ffqueryTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffoffsetTa5d6ff"Tb4b4b4, T79c0ff0Tb4b4b4)Tb4b4b4)
Te6edf3search Tff7b72= Te6edf3requestTff7b72.Td2a8ffqueryTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffsearchTa5d6ff"Tb4b4b4, Tff7b72NoneTb4b4b4)
Te6edf3history Tff7b72= Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8fftelephoneTff7b72.Td2a8ffget_call_historyTb4b4b4(
Te6edf3searchTff7b72=Te6edf3searchTb4b4b4,
Te6edf3limitTff7b72=Te6edf3limitTb4b4b4,
Te6edf3offsetTff7b72=Te6edf3offsetTb4b4b4,
Tb4b4b4)

Te6edf3call_history Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72for Te6edf3row Tff7b72in Te6edf3historyTb4b4b4:
Te6edf3d Tff7b72= Tffa657dictTb4b4b4(Te6edf3rowTb4b4b4)
Te6edf3remote_identity_hash Tff7b72= Te6edf3dTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffremote_identity_hashTa5d6ff"Tb4b4b4)
Tff7b72if Te6edf3remote_identity_hashTb4b4b4:
T8b949e# try to resolve name if unknown or missing
Tff7b72if Tb4b4b4(
Tff7b72not Te6edf3dTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffremote_identity_nameTa5d6ff"Tb4b4b4)
Tff7b72or Te6edf3dTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffremote_identity_nameTa5d6ff"Tb4b4b4) Tff7b72== Ta5d6ff"Ta5d6ffUnknownTa5d6ff"
Tb4b4b4)Tb4b4b4:
Te6edf3resolved_name Tff7b72= Te6edf3appTff7b72.Td2a8ffget_name_for_identity_hashTb4b4b4(
Te6edf3remote_identity_hashTb4b4b4,
Tb4b4b4)
Tff7b72if Te6edf3resolved_nameTb4b4b4:
Te6edf3dTb4b4b4[Ta5d6ff"Ta5d6ffremote_identity_nameTa5d6ff"Tb4b4b4] Tff7b72= Te6edf3resolved_name

Te6edf3lxmf_hash Tff7b72= Te6edf3appTff7b72.Td2a8ffget_lxmf_destination_hash_for_identity_hashTb4b4b4(
Te6edf3remote_identity_hashTb4b4b4,
Tb4b4b4)
Te6edf3tele_hash Tff7b72= Te6edf3appTff7b72.Td2a8ffget_lxst_telephony_hash_for_identity_hashTb4b4b4(
Te6edf3remote_identity_hashTb4b4b4,
Tb4b4b4)
Tff7b72if Te6edf3lxmf_hashTb4b4b4:
Te6edf3dTb4b4b4[Ta5d6ff"Ta5d6ffremote_destination_hashTa5d6ff"Tb4b4b4] Tff7b72= Te6edf3lxmf_hash
Te6edf3icon Tff7b72= Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8ffmiscTff7b72.Td2a8ffget_user_iconTb4b4b4(Te6edf3lxmf_hashTb4b4b4)
Tff7b72if Te6edf3iconTb4b4b4:
Te6edf3dTb4b4b4[Ta5d6ff"Ta5d6ffremote_iconTa5d6ff"Tb4b4b4] Tff7b72= Tffa657dictTb4b4b4(Te6edf3iconTb4b4b4)
Tff7b72if Te6edf3tele_hashTb4b4b4:
Te6edf3dTb4b4b4[Ta5d6ff"Ta5d6ffremote_telephony_hashTa5d6ff"Tb4b4b4] Tff7b72= Te6edf3tele_hash

Te6edf3contact Tff7b72= Te6edf3appTff7b72.Td2a8ff_resolve_contact_for_hashTb4b4b4(Te6edf3remote_identity_hashTb4b4b4)
Te6edf3dTb4b4b4[Ta5d6ff"Ta5d6ffis_contactTa5d6ff"Tb4b4b4] Tff7b72= Te6edf3contact Tff7b72is Tff7b72not Tff7b72None
Tff7b72if Te6edf3contactTb4b4b4:
Te6edf3dTb4b4b4[Ta5d6ff"Ta5d6ffcontact_imageTa5d6ff"Tb4b4b4] Tff7b72= Te6edf3contactTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffcustom_imageTa5d6ff"Tb4b4b4)
Te6edf3call_historyTff7b72.Td2a8ffappendTb4b4b4(Te6edf3dTb4b4b4)

Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffcall_historyTa5d6ff"Tb4b4b4: Te6edf3call_historyTb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)

T8b949e# clear call history

T8b949e# clear call history
Tf0883e@routesTff7b72.Td2a8ffdeleteTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/telephone/historyTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8fftelephone_history_clearTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8fftelephoneTff7b72.Td2a8ffclear_call_historyTb4b4b4(Tb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffokTa5d6ff"Tb4b4b4}Tb4b4b4)

T8b949e# switch audio profile

T8b949e# switch audio profile
Tf0883e@routesTff7b72.Td2a8ffpostTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/telephone/switch-audio-profile/Tffd700{profile_id}Ta5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8fftelephone_switch_audio_profileTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Te6edf3profile_id Tff7b72= Te6edf3requestTff7b72.Td2a8ffmatch_infoTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffprofile_idTa5d6ff"Tb4b4b4)
Tff7b72tryTb4b4b4:
Tff7b72if Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8fftelephone Tff7b72is Tff7b72NoneTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffTelephone not initializedTa5d6ff"Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff400Tb4b4b4,
Tb4b4b4)

Te6edf3resolved Tff7b72= Tff7b72await Te6edf3asyncioTff7b72.Td2a8ffto_threadTb4b4b4(
Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8ffapply_preferred_profileTb4b4b4,
Tffa657intTb4b4b4(Te6edf3profile_idTb4b4b4)Tb4b4b4,
Tb4b4b4)
Te6edf3appTff7b72.Td2a8ffconfigTff7b72.Td2a8fftelephone_audio_profile_idTff7b72.Td2a8ffsetTb4b4b4(Te6edf3resolvedTb4b4b4)
Te6edf3requested Tff7b72= Tffa657intTb4b4b4(Te6edf3profile_idTb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6fffTa5d6ff"Ta5d6ffSwitched to profile Tffd700{Te6edf3resolvedTffd700}Ta5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffprofile_idTa5d6ff"Tb4b4b4: Te6edf3resolvedTb4b4b4,
Ta5d6ff"Ta5d6ffrequested_profile_idTa5d6ff"Tb4b4b4: Te6edf3requestedTb4b4b4,
Ta5d6ff"Ta5d6ffremappedTa5d6ff"Tb4b4b4: Te6edf3requested Tff7b72!= Te6edf3resolvedTb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4}Tb4b4b4, Te6edf3statusTff7b72=T79c0ff500Tb4b4b4)

T8b949e# Codec2 / audio backend readiness (Android packaging + LXST)

T8b949e# Codec2 / audio backend readiness (Android packaging + LXST)
Tf0883e@routesTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/telephone/codec2/statusTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8fftelephone_codec2_statusTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Tff7b72from T7ee787meshchatx Tff7b72import Te6edf3android_codec2

Tff7b72def Td2a8ff_statusTb4b4b4(Tb4b4b4)Tb4b4b4:
Te6edf3probe_okTb4b4b4, Te6edf3probe_error Tff7b72= Te6edf3android_codec2Tff7b72.Td2a8ffprobe_pycodec2Tb4b4b4(Tb4b4b4)
Te6edf3lxst_ok Tff7b72= Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8ffcodec2_availableTb4b4b4(Tb4b4b4)
Te6edf3available Tff7b72= Tffa657boolTb4b4b4(Te6edf3probe_ok Tff7b72and Te6edf3lxst_okTb4b4b4)
Tff7b72return Tb4b4b4{
Ta5d6ff"Ta5d6ffcodec2_availableTa5d6ff"Tb4b4b4: Te6edf3availableTb4b4b4,
Ta5d6ff"Ta5d6ffpreload_errorTa5d6ff"Tb4b4b4: Te6edf3android_codec2Tff7b72.Td2a8ffcodec2_preload_errorTb4b4b4(Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffprobe_errorTa5d6ff"Tb4b4b4: Tff7b72None Tff7b72if Te6edf3probe_ok Tff7b72else Te6edf3probe_errorTb4b4b4,
Ta5d6ff"Ta5d6ffplatformTa5d6ff"Tb4b4b4: Tb4b4b4(
Ta5d6ff"Ta5d6ffandroidTa5d6ff" Tff7b72if Te6edf3android_codec2Tff7b72.Td2a8ff_is_chaquopy_androidTb4b4b4(Tb4b4b4) Tff7b72else Ta5d6ff"Ta5d6ffdesktopTa5d6ff"
Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffpreferred_profile_idTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8ffpreferred_profile_idTb4b4b4,
Ta5d6ff"Ta5d6ffresolved_profile_idTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8ffresolve_audio_profile_idTb4b4b4(Tb4b4b4)Tb4b4b4,
Tb4b4b4}

Te6edf3payload Tff7b72= Tff7b72await Te6edf3asyncioTff7b72.Td2a8ffto_threadTb4b4b4(Te6edf3_statusTb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Te6edf3payloadTb4b4b4)

T8b949e# initiate a telephone call
T8b949e# initiate outgoing telephone call

T8b949e# initiate a telephone call
T8b949e# initiate outgoing telephone call
Tf0883e@routesTff7b72.Td2a8ffpostTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/telephone/call/Tffd700{identity_hash}Ta5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8fftelephone_callTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
T8b949e# make sure telephone enabled
Tff7b72if Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8fftelephone Tff7b72is Tff7b72NoneTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffTelephone has been disabled.Ta5d6ff"Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff503Tb4b4b4,
Tb4b4b4)

T8b949e# check if busy, but ignore stale busy when no active call
Te6edf3is_busy Tff7b72= Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8fftelephoneTff7b72.Td2a8ffbusy
Tff7b72if Te6edf3is_busy Tff7b72and Tff7b72not Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8fftelephoneTff7b72.Td2a8ffactive_callTb4b4b4:
T8b949e# If there's no active call and we're not currently initiating,
T8b949e# we shouldn't be busy.
Tff7b72if Tff7b72not Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8ffinitiation_statusTb4b4b4:
Te6edf3is_busy Tff7b72= Tff7b72False

Tff7b72if Te6edf3is_busy Tff7b72or Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8ffinitiation_statusTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffTelephone is busyTa5d6ff"Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff400Tb4b4b4,
Tb4b4b4)

T8b949e# get path params
Te6edf3identity_hash_hex Tff7b72= Te6edf3requestTff7b72.Td2a8ffmatch_infoTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffidentity_hashTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff"Tb4b4b4)
Tff7b72from T7ee787meshchatxT7ee787.T7ee787srcT7ee787.T7ee787backendT7ee787.T7ee787call_timeout Tff7b72import Te6edf3clamp_call_timeout_seconds

Te6edf3timeout_seconds Tff7b72= Te6edf3clamp_call_timeout_secondsTb4b4b4(
Te6edf3requestTff7b72.Td2a8ffqueryTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fftimeoutTa5d6ff"Tb4b4b4, T79c0ff15Tb4b4b4)Tb4b4b4,
Tb4b4b4)

Tff7b72tryTb4b4b4:
T8b949e# convert hash to bytes
Te6edf3identity_hash_bytes Tff7b72= Tffa657bytesTff7b72.Td2a8fffromhexTb4b4b4(Te6edf3identity_hash_hexTb4b4b4)
Tff7b72except Tf85149ExceptionTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffInvalid identity hashTa5d6ff"Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff400Tb4b4b4,
Tb4b4b4)

Tff7b72if Te6edf3appTff7b72.Td2a8ffis_destination_blockedTb4b4b4(Te6edf3identity_hash_hexTb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffCannot call a banished identityTa5d6ff"Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff403Tb4b4b4,
Tb4b4b4)

T8b949e# initiate call in background to be non-blocking for the UI
Tff7b72async Tff7b72def Td2a8ff_initiateTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Tff7b72await Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8ffinitiateTb4b4b4(
Te6edf3identity_hash_bytesTb4b4b4,
Te6edf3timeout_secondsTff7b72=Te6edf3timeout_secondsTb4b4b4,
Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffFailed to initiate call to Tffd700{Te6edf3identity_hash_hexTffd700}Ta5d6ff: Tffd700{Te6edf3eTffd700}Ta5d6ff"Tb4b4b4)

Te6edf3asyncioTff7b72.Td2a8ffcreate_taskTb4b4b4(Te6edf3_initiateTb4b4b4(Tb4b4b4)Tb4b4b4)

Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffCall initiation startedTa5d6ff"Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)

T8b949e# serve list of available audio profiles

T8b949e# serve list of available audio profiles
Tf0883e@routesTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/telephone/audio-profilesTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8fftelephone_audio_profilesTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Tff7b72from T7ee787LXSTT7ee787.T7ee787PrimitivesT7ee787.T7ee787Telephony Tff7b72import Te6edf3Profiles
Tff7b72from T7ee787meshchatx Tff7b72import Te6edf3android_codec2

Tff7b72def Td2a8ff_profilesTb4b4b4(Tb4b4b4)Tb4b4b4:
Te6edf3probe_okTb4b4b4, Te6edf3_probe_err Tff7b72= Te6edf3android_codec2Tff7b72.Td2a8ffprobe_pycodec2Tb4b4b4(Tb4b4b4)
Te6edf3codec2_ok Tff7b72= Tffa657boolTb4b4b4(Te6edf3probe_ok Tff7b72and Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8ffcodec2_availableTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3codec2_ids Tff7b72= Tb4b4b4{
Te6edf3ProfilesTff7b72.Td2a8ffBANDWIDTH_ULTRA_LOWTb4b4b4,
Te6edf3ProfilesTff7b72.Td2a8ffBANDWIDTH_VERY_LOWTb4b4b4,
Te6edf3ProfilesTff7b72.Td2a8ffBANDWIDTH_LOWTb4b4b4,
Tb4b4b4}
Te6edf3audio_profiles Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72for Te6edf3profile_id Tff7b72in Te6edf3ProfilesTff7b72.Td2a8ffavailable_profilesTb4b4b4(Tb4b4b4)Tb4b4b4:
Te6edf3entry Tff7b72= Tb4b4b4{
Ta5d6ff"Ta5d6ffidTa5d6ff"Tb4b4b4: Te6edf3profile_idTb4b4b4,
Ta5d6ff"Ta5d6ffnameTa5d6ff"Tb4b4b4: Te6edf3ProfilesTff7b72.Td2a8ffprofile_nameTb4b4b4(Te6edf3profile_idTb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffavailableTa5d6ff"Tb4b4b4: Tff7b72TrueTb4b4b4,
Tb4b4b4}
Tff7b72if Te6edf3profile_id Tff7b72in Te6edf3codec2_ids Tff7b72and Tff7b72not Te6edf3codec2_okTb4b4b4:
Te6edf3entryTb4b4b4[Ta5d6ff"Ta5d6ffavailableTa5d6ff"Tb4b4b4] Tff7b72= Tff7b72False
Te6edf3entryTb4b4b4[Ta5d6ff"Ta5d6ffunavailable_reasonTa5d6ff"Tb4b4b4] Tff7b72= Ta5d6ff"Ta5d6ffcodec2Ta5d6ff"
Te6edf3audio_profilesTff7b72.Td2a8ffappendTb4b4b4(Te6edf3entryTb4b4b4)
Tff7b72return Tb4b4b4{
Ta5d6ff"Ta5d6ffdefault_audio_profile_idTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8ffresolve_audio_profile_idTb4b4b4(
Te6edf3ProfilesTff7b72.Td2a8ffDEFAULT_PROFILETb4b4b4,
Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffcodec2_availableTa5d6ff"Tb4b4b4: Te6edf3codec2_okTb4b4b4,
Ta5d6ff"Ta5d6ffaudio_profilesTa5d6ff"Tb4b4b4: Te6edf3audio_profilesTb4b4b4,
Tb4b4b4}

Te6edf3payload Tff7b72= Tff7b72await Te6edf3asyncioTff7b72.Td2a8ffto_threadTb4b4b4(Te6edf3_profilesTb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Te6edf3payloadTb4b4b4)

T8b949e# voicemail status

T8b949e# voicemail status
Tf0883e@routesTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/telephone/voicemail/statusTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8fftelephone_voicemail_statusTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Te6edf3greeting_path Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(
Te6edf3appTff7b72.Td2a8ffvoicemail_managerTff7b72.Td2a8ffgreetings_dirTb4b4b4,
Ta5d6ff"Ta5d6ffgreeting.opusTa5d6ff"Tb4b4b4,
Tb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffhas_espeakTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8ffvoicemail_managerTff7b72.Td2a8ffhas_espeakTb4b4b4,
Ta5d6ff"Ta5d6ffis_recordingTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8ffvoicemail_managerTff7b72.Td2a8ffis_recordingTb4b4b4,
Ta5d6ff"Ta5d6ffis_greeting_recordingTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8ffvoicemail_managerTff7b72.Td2a8ffis_greeting_recordingTb4b4b4,
Ta5d6ff"Ta5d6ffhas_greetingTa5d6ff"Tb4b4b4: Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Te6edf3greeting_pathTb4b4b4)Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)

T8b949e# start recording greeting from mic

T8b949e# start recording greeting from mic
Tf0883e@routesTff7b72.Td2a8ffpostTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/telephone/voicemail/greeting/record/startTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8fftelephone_voicemail_greeting_record_startTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Te6edf3appTff7b72.Td2a8ffvoicemail_managerTff7b72.Td2a8ffstart_greeting_recordingTb4b4b4(Tb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffStarted recording greetingTa5d6ff"Tb4b4b4}Tb4b4b4)

T8b949e# stop recording greeting from mic

T8b949e# stop recording greeting from mic
Tf0883e@routesTff7b72.Td2a8ffpostTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/telephone/voicemail/greeting/record/stopTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8fftelephone_voicemail_greeting_record_stopTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Te6edf3appTff7b72.Td2a8ffvoicemail_managerTff7b72.Td2a8ffstop_greeting_recordingTb4b4b4(Tb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffStopped recording greetingTa5d6ff"Tb4b4b4}Tb4b4b4)

T8b949e# list voicemails

T8b949e# list voicemails
Tf0883e@routesTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/telephone/voicemailsTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8fftelephone_voicemailsTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Te6edf3search Tff7b72= Te6edf3requestTff7b72.Td2a8ffqueryTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffsearchTa5d6ff"Tb4b4b4)
Te6edf3limit Tff7b72= Tffa657intTb4b4b4(Te6edf3requestTff7b72.Td2a8ffqueryTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fflimitTa5d6ff"Tb4b4b4, T79c0ff50Tb4b4b4)Tb4b4b4)
Te6edf3offset Tff7b72= Tffa657intTb4b4b4(Te6edf3requestTff7b72.Td2a8ffqueryTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffoffsetTa5d6ff"Tb4b4b4, T79c0ff0Tb4b4b4)Tb4b4b4)
Te6edf3voicemails_rows Tff7b72= Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8ffvoicemailsTff7b72.Td2a8ffget_voicemailsTb4b4b4(
Te6edf3searchTff7b72=Te6edf3searchTb4b4b4,
Te6edf3limitTff7b72=Te6edf3limitTb4b4b4,
Te6edf3offsetTff7b72=Te6edf3offsetTb4b4b4,
Tb4b4b4)

Te6edf3voicemails Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72for Te6edf3row Tff7b72in Te6edf3voicemails_rowsTb4b4b4:
Te6edf3d Tff7b72= Tffa657dictTb4b4b4(Te6edf3rowTb4b4b4)
Te6edf3remote_identity_hash Tff7b72= Te6edf3dTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffremote_identity_hashTa5d6ff"Tb4b4b4)
Tff7b72if Te6edf3remote_identity_hashTb4b4b4:
Te6edf3lxmf_hash Tff7b72= Te6edf3appTff7b72.Td2a8ffget_lxmf_destination_hash_for_identity_hashTb4b4b4(
Te6edf3remote_identity_hashTb4b4b4,
Tb4b4b4)
Te6edf3tele_hash Tff7b72= Te6edf3appTff7b72.Td2a8ffget_lxst_telephony_hash_for_identity_hashTb4b4b4(
Te6edf3remote_identity_hashTb4b4b4,
Tb4b4b4)
Tff7b72if Te6edf3lxmf_hashTb4b4b4:
Te6edf3dTb4b4b4[Ta5d6ff"Ta5d6ffremote_destination_hashTa5d6ff"Tb4b4b4] Tff7b72= Te6edf3lxmf_hash
Te6edf3icon Tff7b72= Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8ffmiscTff7b72.Td2a8ffget_user_iconTb4b4b4(Te6edf3lxmf_hashTb4b4b4)
Tff7b72if Te6edf3iconTb4b4b4:
Te6edf3dTb4b4b4[Ta5d6ff"Ta5d6ffremote_iconTa5d6ff"Tb4b4b4] Tff7b72= Tffa657dictTb4b4b4(Te6edf3iconTb4b4b4)
Tff7b72if Te6edf3tele_hashTb4b4b4:
Te6edf3dTb4b4b4[Ta5d6ff"Ta5d6ffremote_telephony_hashTa5d6ff"Tb4b4b4] Tff7b72= Te6edf3tele_hash
Te6edf3voicemailsTff7b72.Td2a8ffappendTb4b4b4(Te6edf3dTb4b4b4)

Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffvoicemailsTa5d6ff"Tb4b4b4: Te6edf3voicemailsTb4b4b4,
Ta5d6ff"Ta5d6ffunread_countTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8ffvoicemailsTff7b72.Td2a8ffget_unread_countTb4b4b4(Tb4b4b4)Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)

T8b949e# mark voicemail as read

T8b949e# mark voicemail as read
Tf0883e@routesTff7b72.Td2a8ffpostTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/telephone/voicemails/Tffd700{id}Ta5d6ff/readTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8fftelephone_voicemail_mark_readTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Te6edf3voicemail_id Tff7b72= Te6edf3requestTff7b72.Td2a8ffmatch_infoTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffidTa5d6ff"Tb4b4b4)
Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8ffvoicemailsTff7b72.Td2a8ffmark_as_readTb4b4b4(Te6edf3voicemail_idTb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffVoicemail marked as readTa5d6ff"Tb4b4b4}Tb4b4b4)

T8b949e# delete voicemail

T8b949e# delete voicemail
Tf0883e@routesTff7b72.Td2a8ffdeleteTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/telephone/voicemails/Tffd700{id}Ta5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8fftelephone_voicemail_deleteTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Te6edf3voicemail_id Tff7b72= Te6edf3requestTff7b72.Td2a8ffmatch_infoTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffidTa5d6ff"Tb4b4b4)
Te6edf3voicemail Tff7b72= Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8ffvoicemailsTff7b72.Td2a8ffget_voicemailTb4b4b4(Te6edf3voicemail_idTb4b4b4)
Tff7b72if Te6edf3voicemailTb4b4b4:
Te6edf3filepath Tff7b72= Te6edf3safe_path_under_dirTb4b4b4(
Te6edf3appTff7b72.Td2a8ffvoicemail_managerTff7b72.Td2a8ffrecordings_dirTb4b4b4,
Te6edf3voicemailTb4b4b4[Ta5d6ff"Ta5d6fffilenameTa5d6ff"Tb4b4b4]Tb4b4b4,
Tb4b4b4)
Tff7b72if Te6edf3filepath Tff7b72and Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Te6edf3filepathTb4b4b4)Tb4b4b4:
Te6edf3osTff7b72.Td2a8ffremoveTb4b4b4(Te6edf3filepathTb4b4b4)
Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8ffvoicemailsTff7b72.Td2a8ffdelete_voicemailTb4b4b4(Te6edf3voicemail_idTb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffVoicemail deletedTa5d6ff"Tb4b4b4}Tb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffVoicemail not foundTa5d6ff"Tb4b4b4}Tb4b4b4, Te6edf3statusTff7b72=T79c0ff404Tb4b4b4)

T8b949e# serve greeting audio

T8b949e# serve greeting audio
Tf0883e@routesTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/telephone/voicemail/greeting/audioTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8fftelephone_voicemail_greeting_audioTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Te6edf3filepath Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(
Te6edf3appTff7b72.Td2a8ffvoicemail_managerTff7b72.Td2a8ffgreetings_dirTb4b4b4,
Ta5d6ff"Ta5d6ffgreeting.opusTa5d6ff"Tb4b4b4,
Tb4b4b4)
Tff7b72if Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Te6edf3filepathTb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffFileResponseTb4b4b4(
Te6edf3filepathTb4b4b4,
Te6edf3headersTff7b72=Tb4b4b4{Ta5d6ff"Ta5d6ffContent-TypeTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffaudio/opusTa5d6ff"Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffGreeting audio not foundTa5d6ff"Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff404Tb4b4b4,
Tb4b4b4)

T8b949e# serve voicemail audio

T8b949e# serve voicemail audio
Tf0883e@routesTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/telephone/voicemails/Tffd700{id}Ta5d6ff/audioTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8fftelephone_voicemail_audioTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Te6edf3voicemail_id Tff7b72= Te6edf3requestTff7b72.Td2a8ffmatch_infoTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffidTa5d6ff"Tb4b4b4)
Tff7b72tryTb4b4b4:
Te6edf3voicemail_id Tff7b72= Tffa657intTb4b4b4(Te6edf3voicemail_idTb4b4b4)
Tff7b72except Tb4b4b4(Tf85149ValueErrorTb4b4b4, Tf85149TypeErrorTb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffInvalid voicemail IDTa5d6ff"Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff400Tb4b4b4,
Tb4b4b4)

Tff7b72if Tff7b72not Te6edf3appTff7b72.Td2a8ffvoicemail_managerTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffVoicemail manager not availableTa5d6ff"Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff503Tb4b4b4,
Tb4b4b4)

Te6edf3voicemail Tff7b72= Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8ffvoicemailsTff7b72.Td2a8ffget_voicemailTb4b4b4(Te6edf3voicemail_idTb4b4b4)
Tff7b72if Te6edf3voicemailTb4b4b4:
Te6edf3filepath Tff7b72= Te6edf3safe_path_under_dirTb4b4b4(
Te6edf3appTff7b72.Td2a8ffvoicemail_managerTff7b72.Td2a8ffrecordings_dirTb4b4b4,
Te6edf3voicemailTb4b4b4[Ta5d6ff"Ta5d6fffilenameTa5d6ff"Tb4b4b4]Tb4b4b4,
Tb4b4b4)
Tff7b72if Te6edf3filepath Tff7b72and Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Te6edf3filepathTb4b4b4)Tb4b4b4:
T8b949e# Browsers might need a proper content type for .opus files
Tff7b72return Te6edf3webTff7b72.Td2a8ffFileResponseTb4b4b4(
Te6edf3filepathTb4b4b4,
Te6edf3headersTff7b72=Tb4b4b4{Ta5d6ff"Ta5d6ffContent-TypeTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffaudio/opusTa5d6ff"Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(
Ta5d6fffTa5d6ff"Ta5d6ffVoicemail: Recording file missing for ID Tffd700{Te6edf3voicemail_idTffd700}Ta5d6ff: Tffd700{Te6edf3filepathTffd700}Ta5d6ff"Tb4b4b4,
Te6edf3RNSTff7b72.Td2a8ffLOG_ERRORTb4b4b4,
Tb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffVoicemail audio not foundTa5d6ff"Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff404Tb4b4b4,
Tb4b4b4)

T8b949e# list call recordings

T8b949e# list call recordings
Tf0883e@routesTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/telephone/recordingsTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8fftelephone_recordingsTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Te6edf3search Tff7b72= Te6edf3requestTff7b72.Td2a8ffqueryTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffsearchTa5d6ff"Tb4b4b4, Tff7b72NoneTb4b4b4)
Te6edf3limit Tff7b72= Tffa657intTb4b4b4(Te6edf3requestTff7b72.Td2a8ffqueryTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fflimitTa5d6ff"Tb4b4b4, T79c0ff10Tb4b4b4)Tb4b4b4)
Te6edf3offset Tff7b72= Tffa657intTb4b4b4(Te6edf3requestTff7b72.Td2a8ffqueryTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffoffsetTa5d6ff"Tb4b4b4, T79c0ff0Tb4b4b4)Tb4b4b4)
Te6edf3recordings_rows Tff7b72= Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8fftelephoneTff7b72.Td2a8ffget_call_recordingsTb4b4b4(
Te6edf3searchTff7b72=Te6edf3searchTb4b4b4,
Te6edf3limitTff7b72=Te6edf3limitTb4b4b4,
Te6edf3offsetTff7b72=Te6edf3offsetTb4b4b4,
Tb4b4b4)
Te6edf3recordings Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72for Te6edf3row Tff7b72in Te6edf3recordings_rowsTb4b4b4:
Te6edf3d Tff7b72= Tffa657dictTb4b4b4(Te6edf3rowTb4b4b4)
Te6edf3remote_identity_hash Tff7b72= Te6edf3dTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffremote_identity_hashTa5d6ff"Tb4b4b4)
Tff7b72if Te6edf3remote_identity_hashTb4b4b4:
Te6edf3lxmf_hash Tff7b72= Te6edf3appTff7b72.Td2a8ffget_lxmf_destination_hash_for_identity_hashTb4b4b4(
Te6edf3remote_identity_hashTb4b4b4,
Tb4b4b4)
Tff7b72if Te6edf3lxmf_hashTb4b4b4:
Te6edf3icon Tff7b72= Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8ffmiscTff7b72.Td2a8ffget_user_iconTb4b4b4(Te6edf3lxmf_hashTb4b4b4)
Tff7b72if Te6edf3iconTb4b4b4:
Te6edf3dTb4b4b4[Ta5d6ff"Ta5d6ffremote_iconTa5d6ff"Tb4b4b4] Tff7b72= Tffa657dictTb4b4b4(Te6edf3iconTb4b4b4)
Te6edf3recordingsTff7b72.Td2a8ffappendTb4b4b4(Te6edf3dTb4b4b4)

Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffrecordingsTa5d6ff"Tb4b4b4: Te6edf3recordingsTb4b4b4}Tb4b4b4)

T8b949e# serve call recording audio

T8b949e# serve call recording audio
Tf0883e@routesTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/telephone/recordings/Tffd700{id}Ta5d6ff/audio/Tffd700{side}Ta5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8fftelephone_recording_audioTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Te6edf3recording_id Tff7b72= Te6edf3requestTff7b72.Td2a8ffmatch_infoTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffidTa5d6ff"Tb4b4b4)
Tff7b72tryTb4b4b4:
Te6edf3recording_id Tff7b72= Tffa657intTb4b4b4(Te6edf3recording_idTb4b4b4)
Tff7b72except Tb4b4b4(Tf85149ValueErrorTb4b4b4, Tf85149TypeErrorTb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffInvalid recording IDTa5d6ff"Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff400Tb4b4b4,
Tb4b4b4)

Te6edf3side Tff7b72= Te6edf3requestTff7b72.Td2a8ffmatch_infoTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffsideTa5d6ff"Tb4b4b4)
Tff7b72if Te6edf3side Tff7b72not Tff7b72in Tb4b4b4(Ta5d6ff"Ta5d6ffrxTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6fftxTa5d6ff"Tb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffInvalid recording sideTa5d6ff"Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff400Tb4b4b4,
Tb4b4b4)
Te6edf3recording Tff7b72= Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8fftelephoneTff7b72.Td2a8ffget_call_recordingTb4b4b4(Te6edf3recording_idTb4b4b4)
Tff7b72if Te6edf3recordingTb4b4b4:
Te6edf3filename Tff7b72= Te6edf3recordingTb4b4b4[Ta5d6fffTa5d6ff"Ta5d6fffilename_Tffd700{Te6edf3sideTffd700}Ta5d6ff"Tb4b4b4]
Tff7b72if Tff7b72not Te6edf3filenameTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6fffTa5d6ff"Ta5d6ffNo Tffd700{Te6edf3sideTffd700}Ta5d6ff recording foundTa5d6ff"Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff404Tb4b4b4,
Tb4b4b4)

Te6edf3filepath Tff7b72= Te6edf3safe_path_under_dirTb4b4b4(
Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8ffrecordings_dirTb4b4b4,
Te6edf3filenameTb4b4b4,
Tb4b4b4)
Tff7b72if Te6edf3filepath Tff7b72and Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Te6edf3filepathTb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffFileResponseTb4b4b4(
Te6edf3filepathTb4b4b4,
Te6edf3headersTff7b72=Tb4b4b4{Ta5d6ff"Ta5d6ffContent-TypeTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffaudio/opusTa5d6ff"Tb4b4b4}Tb4b4b4,
Tb4b4b4)

Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffRecording not foundTa5d6ff"Tb4b4b4}Tb4b4b4, Te6edf3statusTff7b72=T79c0ff404Tb4b4b4)

T8b949e# delete call recording

T8b949e# delete call recording
Tf0883e@routesTff7b72.Td2a8ffdeleteTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/telephone/recordings/Tffd700{id}Ta5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8fftelephone_recording_deleteTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Te6edf3recording_id Tff7b72= Te6edf3requestTff7b72.Td2a8ffmatch_infoTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffidTa5d6ff"Tb4b4b4)
Te6edf3recording Tff7b72= Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8fftelephoneTff7b72.Td2a8ffget_call_recordingTb4b4b4(Te6edf3recording_idTb4b4b4)
Tff7b72if Te6edf3recordingTb4b4b4:
Tff7b72for Te6edf3side Tff7b72in Tb4b4b4[Ta5d6ff"Ta5d6ffrxTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6fftxTa5d6ff"Tb4b4b4]Tb4b4b4:
Te6edf3filename Tff7b72= Te6edf3recordingTb4b4b4[Ta5d6fffTa5d6ff"Ta5d6fffilename_Tffd700{Te6edf3sideTffd700}Ta5d6ff"Tb4b4b4]
Tff7b72if Te6edf3filenameTb4b4b4:
Te6edf3filepath Tff7b72= Te6edf3safe_path_under_dirTb4b4b4(
Te6edf3appTff7b72.Td2a8fftelephone_managerTff7b72.Td2a8ffrecordings_dirTb4b4b4,
Te6edf3filenameTb4b4b4,
Tb4b4b4)
Tff7b72if Te6edf3filepath Tff7b72and Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Te6edf3filepathTb4b4b4)Tb4b4b4:
Te6edf3osTff7b72.Td2a8ffremoveTb4b4b4(Te6edf3filepathTb4b4b4)
Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8fftelephoneTff7b72.Td2a8ffdelete_call_recordingTb4b4b4(Te6edf3recording_idTb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffokTa5d6ff"Tb4b4b4}Tb4b4b4)

T8b949e# generate greeting

T8b949e# generate greeting
Tf0883e@routesTff7b72.Td2a8ffpostTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/telephone/voicemail/generate-greetingTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8fftelephone_voicemail_generate_greetingTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3text Tff7b72= Te6edf3appTff7b72.Td2a8ffconfigTff7b72.Td2a8ffvoicemail_greetingTff7b72.Td2a8ffgetTb4b4b4(Tb4b4b4)
Te6edf3path Tff7b72= Tff7b72await Te6edf3asyncioTff7b72.Td2a8ffto_threadTb4b4b4(
Te6edf3appTff7b72.Td2a8ffvoicemail_managerTff7b72.Td2a8ffgenerate_greetingTb4b4b4,
Te6edf3textTb4b4b4,
Tb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffGreeting generatedTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffpathTa5d6ff"Tb4b4b4: Te6edf3pathTb4b4b4}Tb4b4b4,
Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4}Tb4b4b4, Te6edf3statusTff7b72=T79c0ff500Tb4b4b4)

T8b949e# upload greeting

T8b949e# upload greeting
Tf0883e@routesTff7b72.Td2a8ffpostTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/telephone/voicemail/greeting/uploadTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8fftelephone_voicemail_greeting_uploadTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3reader Tff7b72= Tff7b72await Te6edf3requestTff7b72.Td2a8ffmultipartTb4b4b4(Tb4b4b4)
Te6edf3field Tff7b72= Tff7b72await Te6edf3first_multipart_file_fieldTb4b4b4(Te6edf3readerTb4b4b4)
Tff7b72if Te6edf3field Tff7b72is Tff7b72NoneTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffFile field requiredTa5d6ff"Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff400Tb4b4b4,
Tb4b4b4)

Te6edf3filename Tff7b72= Te6edf3fieldTff7b72.Td2a8fffilename Tff7b72or Ta5d6ff"Ta5d6ffuploadTa5d6ff"
Te6edf3extension Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffsplitextTb4b4b4(Te6edf3filenameTb4b4b4)Tb4b4b4[T79c0ff1Tb4b4b4]Tff7b72.Td2a8fflowerTb4b4b4(Tb4b4b4)
Tff7b72if Te6edf3extension Tff7b72not Tff7b72in Tb4b4b4[Ta5d6ff"Ta5d6ff.mp3Ta5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff.oggTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff.wavTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff.m4aTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff.flacTa5d6ff"Tb4b4b4]Tb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6fffTa5d6ff"Ta5d6ffUnsupported file type: Tffd700{Te6edf3extensionTffd700}Ta5d6ff"Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff400Tb4b4b4,
Tb4b4b4)

T8b949e# Save temp file
Tff7b72with Te6edf3tempfileTff7b72.Td2a8ffNamedTemporaryFileTb4b4b4(Te6edf3suffixTff7b72=Te6edf3extensionTb4b4b4, Te6edf3deleteTff7b72=Tff7b72FalseTb4b4b4) Tff7b72as Te6edf3fTb4b4b4:
Te6edf3temp_path Tff7b72= Te6edf3fTff7b72.Td2a8ffname
Tff7b72while Tff7b72TrueTb4b4b4:
Te6edf3chunk Tff7b72= Tff7b72await Te6edf3fieldTff7b72.Td2a8ffread_chunkTb4b4b4(Tb4b4b4)
Tff7b72if Tff7b72not Te6edf3chunkTb4b4b4:
Tff7b72break
Te6edf3fTff7b72.Td2a8ffwriteTb4b4b4(Te6edf3chunkTb4b4b4)

Tff7b72tryTb4b4b4:
T8b949e# Convert to greeting
Te6edf3path Tff7b72= Tff7b72await Te6edf3asyncioTff7b72.Td2a8ffto_threadTb4b4b4(
Te6edf3appTff7b72.Td2a8ffvoicemail_managerTff7b72.Td2a8ffconvert_to_greetingTb4b4b4,
Te6edf3temp_pathTb4b4b4,
Tb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffGreeting uploaded and convertedTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffpathTa5d6ff"Tb4b4b4: Te6edf3pathTb4b4b4}Tb4b4b4,
Tb4b4b4)
Tff7b72finallyTb4b4b4:
Tff7b72if Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Te6edf3temp_pathTb4b4b4)Tb4b4b4:
Te6edf3osTff7b72.Td2a8ffremoveTb4b4b4(Te6edf3temp_pathTb4b4b4)

Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4}Tb4b4b4, Te6edf3statusTff7b72=T79c0ff500Tb4b4b4)

T8b949e# delete greeting

T8b949e# delete greeting
Tf0883e@routesTff7b72.Td2a8ffdeleteTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/telephone/voicemail/greetingTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8fftelephone_voicemail_greeting_deleteTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3appTff7b72.Td2a8ffvoicemail_managerTff7b72.Td2a8ffremove_greetingTb4b4b4(Tb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffGreeting deletedTa5d6ff"Tb4b4b4}Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4}Tb4b4b4, Te6edf3statusTff7b72=T79c0ff500Tb4b4b4)

T8b949e# ringtone routes

T8b949e# ringtone routes
Tf0883e@routesTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/telephone/ringtonesTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8fftelephone_ringtones_getTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Te6edf3ringtones Tff7b72= Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8ffringtonesTff7b72.Td2a8ffget_allTb4b4b4(Tb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4[
Tb4b4b4{
Ta5d6ff"Ta5d6ffidTa5d6ff"Tb4b4b4: Te6edf3rTb4b4b4[Ta5d6ff"Ta5d6ffidTa5d6ff"Tb4b4b4]Tb4b4b4,
Ta5d6ff"Ta5d6fffilenameTa5d6ff"Tb4b4b4: Te6edf3rTb4b4b4[Ta5d6ff"Ta5d6fffilenameTa5d6ff"Tb4b4b4]Tb4b4b4,
Ta5d6ff"Ta5d6ffdisplay_nameTa5d6ff"Tb4b4b4: Te6edf3rTb4b4b4[Ta5d6ff"Ta5d6ffdisplay_nameTa5d6ff"Tb4b4b4]Tb4b4b4,
Ta5d6ff"Ta5d6ffis_primaryTa5d6ff"Tb4b4b4: Tffa657boolTb4b4b4(Te6edf3rTb4b4b4[Ta5d6ff"Ta5d6ffis_primaryTa5d6ff"Tb4b4b4]Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffcreated_atTa5d6ff"Tb4b4b4: Te6edf3rTb4b4b4[Ta5d6ff"Ta5d6ffcreated_atTa5d6ff"Tb4b4b4]Tb4b4b4,
Tb4b4b4}
Tff7b72for Te6edf3r Tff7b72in Te6edf3ringtones
Tb4b4b4]Tb4b4b4,
Tb4b4b4)

Tf0883e@routesTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/telephone/ringtones/statusTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8fftelephone_ringtone_statusTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3caller_hash Tff7b72= Te6edf3requestTff7b72.Td2a8ffqueryTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffcaller_hashTa5d6ff"Tb4b4b4)

Te6edf3ringtone_id Tff7b72= Tff7b72None

T8b949e# 1. check contact preferred ringtone
Tff7b72if Te6edf3caller_hashTb4b4b4:
Te6edf3contact Tff7b72= Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8ffcontactsTff7b72.Td2a8ffget_contact_by_identity_hashTb4b4b4(
Te6edf3caller_hashTb4b4b4,
Tb4b4b4)
Tff7b72if Te6edf3contact Tff7b72and Te6edf3contactTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffpreferred_ringtone_idTa5d6ff"Tb4b4b4)Tb4b4b4:
Te6edf3ringtone_id Tff7b72= Te6edf3contactTb4b4b4[Ta5d6ff"Ta5d6ffpreferred_ringtone_idTa5d6ff"Tb4b4b4]

T8b949e# 2. check global preferred for non-contacts
Tff7b72if Te6edf3ringtone_id Tff7b72is Tff7b72NoneTb4b4b4:
Te6edf3preferred_id Tff7b72= Te6edf3appTff7b72.Td2a8ffconfigTff7b72.Td2a8ffringtone_preferred_idTff7b72.Td2a8ffgetTb4b4b4(Tb4b4b4)
Tff7b72if Te6edf3preferred_idTb4b4b4:
Te6edf3ringtone_id Tff7b72= Te6edf3preferred_id

T8b949e# 3. fallback to primary
Tff7b72if Te6edf3ringtone_id Tff7b72is Tff7b72NoneTb4b4b4:
Te6edf3primary Tff7b72= Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8ffringtonesTff7b72.Td2a8ffget_primaryTb4b4b4(Tb4b4b4)
Tff7b72if Te6edf3primaryTb4b4b4:
Te6edf3ringtone_id Tff7b72= Te6edf3primaryTb4b4b4[Ta5d6ff"Ta5d6ffidTa5d6ff"Tb4b4b4]

T8b949e# 4. handle random if selected (-1)
Tff7b72if Te6edf3ringtone_id Tff7b72== Tff7b72-T79c0ff1Tb4b4b4:
Tff7b72import T7ee787random

Te6edf3ringtones Tff7b72= Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8ffringtonesTff7b72.Td2a8ffget_allTb4b4b4(Tb4b4b4)
Tff7b72if Te6edf3ringtonesTb4b4b4:
Te6edf3ringtone_id Tff7b72= Te6edf3randomTff7b72.Td2a8ffchoiceTb4b4b4(Te6edf3ringtonesTb4b4b4)Tb4b4b4[Ta5d6ff"Ta5d6ffidTa5d6ff"Tb4b4b4]
Tff7b72elseTb4b4b4:
Te6edf3ringtone_id Tff7b72= Tff7b72None

Te6edf3has_custom Tff7b72= Te6edf3ringtone_id Tff7b72is Tff7b72not Tff7b72None
Te6edf3ringtone Tff7b72= Tb4b4b4(
Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8ffringtonesTff7b72.Td2a8ffget_by_idTb4b4b4(Te6edf3ringtone_idTb4b4b4) Tff7b72if Te6edf3has_custom Tff7b72else Tff7b72None
Tb4b4b4)

Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffhas_custom_ringtoneTa5d6ff"Tb4b4b4: Te6edf3has_custom Tff7b72and Te6edf3ringtone Tff7b72is Tff7b72not Tff7b72NoneTb4b4b4,
Ta5d6ff"Ta5d6ffenabledTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8ffconfigTff7b72.Td2a8ffcustom_ringtone_enabledTff7b72.Td2a8ffgetTb4b4b4(Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6fffilenameTa5d6ff"Tb4b4b4: Te6edf3ringtoneTb4b4b4[Ta5d6ff"Ta5d6fffilenameTa5d6ff"Tb4b4b4] Tff7b72if Te6edf3ringtone Tff7b72else Tff7b72NoneTb4b4b4,
Ta5d6ff"Ta5d6ffidTa5d6ff"Tb4b4b4: Te6edf3ringtone_id Tff7b72if Te6edf3ringtone_id Tff7b72!= Tff7b72-T79c0ff1 Tff7b72else Tff7b72NoneTb4b4b4,
Ta5d6ff"Ta5d6ffvolumeTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8ffconfigTff7b72.Td2a8ffringtone_volumeTff7b72.Td2a8ffgetTb4b4b4(Tb4b4b4) Tff7b72/ T79c0ff100.0Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Te6edf3loggerTff7b72.Td2a8fferrorTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffError in telephone_ringtone_status: Tffd700{Te6edf3eTffd700}Ta5d6ff"Tb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffhas_custom_ringtoneTa5d6ff"Tb4b4b4: Tff7b72FalseTb4b4b4,
Ta5d6ff"Ta5d6ffenabledTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8ffconfigTff7b72.Td2a8ffcustom_ringtone_enabledTff7b72.Td2a8ffgetTb4b4b4(Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6fffilenameTa5d6ff"Tb4b4b4: Tff7b72NoneTb4b4b4,
Ta5d6ff"Ta5d6ffidTa5d6ff"Tb4b4b4: Tff7b72NoneTb4b4b4,
Ta5d6ff"Ta5d6ffvolumeTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8ffconfigTff7b72.Td2a8ffringtone_volumeTff7b72.Td2a8ffgetTb4b4b4(Tb4b4b4) Tff7b72/ T79c0ff100.0Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)

Tf0883e@routesTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/telephone/ringtones/Tffd700{id}Ta5d6ff/audioTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8fftelephone_ringtone_audioTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Te6edf3ringtone_id Tff7b72= Tffa657intTb4b4b4(Te6edf3requestTff7b72.Td2a8ffmatch_infoTb4b4b4[Ta5d6ff"Ta5d6ffidTa5d6ff"Tb4b4b4]Tb4b4b4)
Te6edf3ringtone Tff7b72= Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8ffringtonesTff7b72.Td2a8ffget_by_idTb4b4b4(Te6edf3ringtone_idTb4b4b4)
Tff7b72if Tff7b72not Te6edf3ringtoneTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffRingtone not foundTa5d6ff"Tb4b4b4}Tb4b4b4, Te6edf3statusTff7b72=T79c0ff404Tb4b4b4)

Te6edf3download Tff7b72= Te6edf3requestTff7b72.Td2a8ffqueryTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffdownloadTa5d6ff"Tb4b4b4) Tff7b72== Ta5d6ff"Ta5d6ff1Ta5d6ff"

Te6edf3filepath Tff7b72= Te6edf3appTff7b72.Td2a8ffringtone_managerTff7b72.Td2a8ffget_ringtone_pathTb4b4b4(
Te6edf3ringtoneTb4b4b4[Ta5d6ff"Ta5d6ffstorage_filenameTa5d6ff"Tb4b4b4]Tb4b4b4,
Tb4b4b4)
Tff7b72if Te6edf3filepath Tff7b72and Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Te6edf3filepathTb4b4b4)Tb4b4b4:
Tff7b72if Te6edf3downloadTb4b4b4:
Te6edf3safe_name Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffbasenameTb4b4b4(
Tffa657strTb4b4b4(Te6edf3ringtoneTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fffilenameTa5d6ff"Tb4b4b4) Tff7b72or Ta5d6ff"Ta5d6ffringtone.opusTa5d6ff"Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Te6edf3safe_name Tff7b72= Tb4b4b4(
Te6edf3safe_nameTff7b72.Td2a8ffreplaceTb4b4b4(Ta5d6ff'Ta5d6ff"Ta5d6ff'Tb4b4b4, Ta5d6ff"Ta5d6ff"Tb4b4b4)Tff7b72.Td2a8ffreplaceTb4b4b4(Ta5d6ff"Tffea00\rTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff"Tb4b4b4)Tff7b72.Td2a8ffreplaceTb4b4b4(Ta5d6ff"Tffea00\nTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff"Tb4b4b4)
Tff7b72or Ta5d6ff"Ta5d6ffringtone.opusTa5d6ff"
Tb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffFileResponseTb4b4b4(
Te6edf3filepathTb4b4b4,
Te6edf3headersTff7b72=Tb4b4b4{
Ta5d6ff"Ta5d6ffContent-DispositionTa5d6ff"Tb4b4b4: Ta5d6fffTa5d6ff'Ta5d6ffattachment; filename=Ta5d6ff"Tffd700{Te6edf3safe_nameTffd700}Ta5d6ff"Ta5d6ff'Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffFileResponseTb4b4b4(Te6edf3filepathTb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffRingtone audio file not foundTa5d6ff"Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff404Tb4b4b4,
Tb4b4b4)

Tf0883e@routesTff7b72.Td2a8ffpostTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/telephone/ringtones/uploadTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8fftelephone_ringtone_uploadTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3reader Tff7b72= Tff7b72await Te6edf3requestTff7b72.Td2a8ffmultipartTb4b4b4(Tb4b4b4)
Te6edf3field Tff7b72= Tff7b72await Te6edf3first_multipart_file_fieldTb4b4b4(Te6edf3readerTb4b4b4)
Tff7b72if Te6edf3field Tff7b72is Tff7b72NoneTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffFile field requiredTa5d6ff"Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff400Tb4b4b4,
Tb4b4b4)

Te6edf3filename Tff7b72= Te6edf3fieldTff7b72.Td2a8fffilename Tff7b72or Ta5d6ff"Ta5d6ffuploadTa5d6ff"
Te6edf3extension Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffsplitextTb4b4b4(Te6edf3filenameTb4b4b4)Tb4b4b4[T79c0ff1Tb4b4b4]Tff7b72.Td2a8fflowerTb4b4b4(Tb4b4b4)
Tff7b72if Te6edf3extension Tff7b72not Tff7b72in Tb4b4b4[Ta5d6ff"Ta5d6ff.mp3Ta5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff.oggTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff.wavTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff.m4aTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff.flacTa5d6ff"Tb4b4b4]Tb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6fffTa5d6ff"Ta5d6ffUnsupported file type: Tffd700{Te6edf3extensionTffd700}Ta5d6ff"Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff400Tb4b4b4,
Tb4b4b4)

T8b949e# Save temp file
Tff7b72with Te6edf3tempfileTff7b72.Td2a8ffNamedTemporaryFileTb4b4b4(Te6edf3suffixTff7b72=Te6edf3extensionTb4b4b4, Te6edf3deleteTff7b72=Tff7b72FalseTb4b4b4) Tff7b72as Te6edf3fTb4b4b4:
Te6edf3temp_path Tff7b72= Te6edf3fTff7b72.Td2a8ffname
Tff7b72while Tff7b72TrueTb4b4b4:
Te6edf3chunk Tff7b72= Tff7b72await Te6edf3fieldTff7b72.Td2a8ffread_chunkTb4b4b4(Tb4b4b4)
Tff7b72if Tff7b72not Te6edf3chunkTb4b4b4:
Tff7b72break
Te6edf3fTff7b72.Td2a8ffwriteTb4b4b4(Te6edf3chunkTb4b4b4)

Tff7b72tryTb4b4b4:
T8b949e# Convert to ringtone
Te6edf3storage_filename Tff7b72= Tff7b72await Te6edf3asyncioTff7b72.Td2a8ffto_threadTb4b4b4(
Te6edf3appTff7b72.Td2a8ffringtone_managerTff7b72.Td2a8ffconvert_to_ringtoneTb4b4b4,
Te6edf3temp_pathTb4b4b4,
Tb4b4b4)

T8b949e# Add to database
Te6edf3ringtone_id Tff7b72= Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8ffringtonesTff7b72.Td2a8ffaddTb4b4b4(
Te6edf3filenameTff7b72=Te6edf3filenameTb4b4b4,
Te6edf3storage_filenameTff7b72=Te6edf3storage_filenameTb4b4b4,
Tb4b4b4)

Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffRingtone uploaded and convertedTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffidTa5d6ff"Tb4b4b4: Te6edf3ringtone_idTb4b4b4,
Ta5d6ff"Ta5d6fffilenameTa5d6ff"Tb4b4b4: Te6edf3filenameTb4b4b4,
Ta5d6ff"Ta5d6ffstorage_filenameTa5d6ff"Tb4b4b4: Te6edf3storage_filenameTb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tff7b72finallyTb4b4b4:
Tff7b72if Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Te6edf3temp_pathTb4b4b4)Tb4b4b4:
Te6edf3osTff7b72.Td2a8ffremoveTb4b4b4(Te6edf3temp_pathTb4b4b4)

Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4}Tb4b4b4, Te6edf3statusTff7b72=T79c0ff500Tb4b4b4)

Tf0883e@routesTff7b72.Td2a8ffpatchTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/telephone/ringtones/Tffd700{id}Ta5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8fftelephone_ringtone_patchTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3ringtone_id Tff7b72= Tffa657intTb4b4b4(Te6edf3requestTff7b72.Td2a8ffmatch_infoTb4b4b4[Ta5d6ff"Ta5d6ffidTa5d6ff"Tb4b4b4]Tb4b4b4)
Te6edf3data Tff7b72= Tff7b72await Te6edf3requestTff7b72.Td2a8ffjsonTb4b4b4(Tb4b4b4)

Te6edf3display_name Tff7b72= Te6edf3dataTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffdisplay_nameTa5d6ff"Tb4b4b4)
Te6edf3is_primary Tff7b72= T79c0ff1 Tff7b72if Te6edf3dataTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffis_primaryTa5d6ff"Tb4b4b4) Tff7b72else Tff7b72None

Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8ffringtonesTff7b72.Td2a8ffupdateTb4b4b4(
Te6edf3ringtone_idTb4b4b4,
Te6edf3display_nameTff7b72=Te6edf3display_nameTb4b4b4,
Te6edf3is_primaryTff7b72=Te6edf3is_primaryTb4b4b4,
Tb4b4b4)

Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffRingtone updatedTa5d6ff"Tb4b4b4}Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4}Tb4b4b4, Te6edf3statusTff7b72=T79c0ff500Tb4b4b4)

Tf0883e@routesTff7b72.Td2a8ffdeleteTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/telephone/ringtones/Tffd700{id}Ta5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8fftelephone_ringtone_deleteTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3ringtone_id Tff7b72= Tffa657intTb4b4b4(Te6edf3requestTff7b72.Td2a8ffmatch_infoTb4b4b4[Ta5d6ff"Ta5d6ffidTa5d6ff"Tb4b4b4]Tb4b4b4)
Te6edf3ringtone Tff7b72= Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8ffringtonesTff7b72.Td2a8ffget_by_idTb4b4b4(Te6edf3ringtone_idTb4b4b4)
Tff7b72if Te6edf3ringtoneTb4b4b4:
Te6edf3appTff7b72.Td2a8ffringtone_managerTff7b72.Td2a8ffremove_ringtoneTb4b4b4(Te6edf3ringtoneTb4b4b4[Ta5d6ff"Ta5d6ffstorage_filenameTa5d6ff"Tb4b4b4]Tb4b4b4)
Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8ffringtonesTff7b72.Td2a8ffdeleteTb4b4b4(Te6edf3ringtone_idTb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffRingtone deletedTa5d6ff"Tb4b4b4}Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4}Tb4b4b4, Te6edf3statusTff7b72=T79c0ff500Tb4b4b4)

T8b949e# notification sound routes

T8b949e# notification sound routes
Tf0883e@routesTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/notification-soundsTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8ffnotification_sounds_getTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Te6edf3sounds Tff7b72= Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8ffnotification_soundsTff7b72.Td2a8ffget_allTb4b4b4(Tb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4[
Tb4b4b4{
Ta5d6ff"Ta5d6ffidTa5d6ff"Tb4b4b4: Te6edf3sTb4b4b4[Ta5d6ff"Ta5d6ffidTa5d6ff"Tb4b4b4]Tb4b4b4,
Ta5d6ff"Ta5d6fffilenameTa5d6ff"Tb4b4b4: Te6edf3sTb4b4b4[Ta5d6ff"Ta5d6fffilenameTa5d6ff"Tb4b4b4]Tb4b4b4,
Ta5d6ff"Ta5d6ffdisplay_nameTa5d6ff"Tb4b4b4: Te6edf3sTb4b4b4[Ta5d6ff"Ta5d6ffdisplay_nameTa5d6ff"Tb4b4b4]Tb4b4b4,
Ta5d6ff"Ta5d6ffis_primaryTa5d6ff"Tb4b4b4: Tffa657boolTb4b4b4(Te6edf3sTb4b4b4[Ta5d6ff"Ta5d6ffis_primaryTa5d6ff"Tb4b4b4]Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffcreated_atTa5d6ff"Tb4b4b4: Te6edf3sTb4b4b4[Ta5d6ff"Ta5d6ffcreated_atTa5d6ff"Tb4b4b4]Tb4b4b4,
Tb4b4b4}
Tff7b72for Te6edf3s Tff7b72in Te6edf3sounds
Tb4b4b4]Tb4b4b4,
Tb4b4b4)

Tf0883e@routesTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/notification-sounds/statusTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8ffnotification_sound_statusTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3sound_id Tff7b72= Tff7b72None

Te6edf3preferred_id Tff7b72= Te6edf3appTff7b72.Td2a8ffconfigTff7b72.Td2a8ffnotification_sound_preferred_idTff7b72.Td2a8ffgetTb4b4b4(Tb4b4b4)
Tff7b72if Te6edf3preferred_id Tff7b72and Te6edf3preferred_id Tff7b72> T79c0ff0Tb4b4b4:
Te6edf3sound_id Tff7b72= Te6edf3preferred_id

Tff7b72if Te6edf3sound_id Tff7b72is Tff7b72NoneTb4b4b4:
Te6edf3primary Tff7b72= Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8ffnotification_soundsTff7b72.Td2a8ffget_primaryTb4b4b4(Tb4b4b4)
Tff7b72if Te6edf3primaryTb4b4b4:
Te6edf3sound_id Tff7b72= Te6edf3primaryTb4b4b4[Ta5d6ff"Ta5d6ffidTa5d6ff"Tb4b4b4]

Te6edf3has_sound Tff7b72= Te6edf3sound_id Tff7b72is Tff7b72not Tff7b72None
Te6edf3sound Tff7b72= Tb4b4b4(
Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8ffnotification_soundsTff7b72.Td2a8ffget_by_idTb4b4b4(Te6edf3sound_idTb4b4b4)
Tff7b72if Te6edf3sound_id
Tff7b72else Tff7b72None
Tb4b4b4)

Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffhas_soundTa5d6ff"Tb4b4b4: Te6edf3has_sound Tff7b72and Te6edf3sound Tff7b72is Tff7b72not Tff7b72NoneTb4b4b4,
Ta5d6ff"Ta5d6ffenabledTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8ffconfigTff7b72.Td2a8ffnotification_sound_enabledTff7b72.Td2a8ffgetTb4b4b4(Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6fffilenameTa5d6ff"Tb4b4b4: Te6edf3soundTb4b4b4[Ta5d6ff"Ta5d6fffilenameTa5d6ff"Tb4b4b4] Tff7b72if Te6edf3sound Tff7b72else Tff7b72NoneTb4b4b4,
Ta5d6ff"Ta5d6ffidTa5d6ff"Tb4b4b4: Te6edf3sound_idTb4b4b4,
Ta5d6ff"Ta5d6ffvolumeTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8ffconfigTff7b72.Td2a8ffnotification_sound_volumeTff7b72.Td2a8ffgetTb4b4b4(Tb4b4b4) Tff7b72/ T79c0ff100.0Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Te6edf3loggerTff7b72.Td2a8fferrorTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffError in notification_sound_status: Tffd700{Te6edf3eTffd700}Ta5d6ff"Tb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffhas_soundTa5d6ff"Tb4b4b4: Tff7b72FalseTb4b4b4,
Ta5d6ff"Ta5d6ffenabledTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8ffconfigTff7b72.Td2a8ffnotification_sound_enabledTff7b72.Td2a8ffgetTb4b4b4(Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6fffilenameTa5d6ff"Tb4b4b4: Tff7b72NoneTb4b4b4,
Ta5d6ff"Ta5d6ffidTa5d6ff"Tb4b4b4: Tff7b72NoneTb4b4b4,
Ta5d6ff"Ta5d6ffvolumeTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8ffconfigTff7b72.Td2a8ffnotification_sound_volumeTff7b72.Td2a8ffgetTb4b4b4(Tb4b4b4) Tff7b72/ T79c0ff100.0Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)

Tf0883e@routesTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/notification-sounds/Tffd700{id}Ta5d6ff/audioTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8ffnotification_sound_audioTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Te6edf3sound_id Tff7b72= Tffa657intTb4b4b4(Te6edf3requestTff7b72.Td2a8ffmatch_infoTb4b4b4[Ta5d6ff"Ta5d6ffidTa5d6ff"Tb4b4b4]Tb4b4b4)
Te6edf3sound Tff7b72= Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8ffnotification_soundsTff7b72.Td2a8ffget_by_idTb4b4b4(Te6edf3sound_idTb4b4b4)
Tff7b72if Tff7b72not Te6edf3soundTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffResponseTb4b4b4(Te6edf3statusTff7b72=T79c0ff404Tb4b4b4)

Tff7b72if Tff7b72not Te6edf3appTff7b72.Td2a8ffnotification_sound_managerTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffResponseTb4b4b4(Te6edf3statusTff7b72=T79c0ff503Tb4b4b4)

Te6edf3filepath Tff7b72= Te6edf3appTff7b72.Td2a8ffnotification_sound_managerTff7b72.Td2a8ffget_ringtone_pathTb4b4b4(
Te6edf3soundTb4b4b4[Ta5d6ff"Ta5d6ffstorage_filenameTa5d6ff"Tb4b4b4]Tb4b4b4,
Tb4b4b4)
Tff7b72if Tff7b72not Te6edf3filepath Tff7b72or Tff7b72not Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Te6edf3filepathTb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffResponseTb4b4b4(Te6edf3statusTff7b72=T79c0ff404Tb4b4b4)

Te6edf3safe_name Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffbasenameTb4b4b4(Tffa657strTb4b4b4(Te6edf3soundTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fffilenameTa5d6ff"Tb4b4b4) Tff7b72or Ta5d6ff"Ta5d6ffsound.opusTa5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3safe_name Tff7b72= Tb4b4b4(
Te6edf3safe_nameTff7b72.Td2a8ffreplaceTb4b4b4(Ta5d6ff'Ta5d6ff"Ta5d6ff'Tb4b4b4, Ta5d6ff"Ta5d6ff"Tb4b4b4)Tff7b72.Td2a8ffreplaceTb4b4b4(Ta5d6ff"Tffea00\rTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff"Tb4b4b4)Tff7b72.Td2a8ffreplaceTb4b4b4(Ta5d6ff"Tffea00\nTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff"Tb4b4b4)
Tff7b72or Ta5d6ff"Ta5d6ffsound.opusTa5d6ff"
Tb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffFileResponseTb4b4b4(
Te6edf3filepathTb4b4b4,
Te6edf3headersTff7b72=Tb4b4b4{
Ta5d6ff"Ta5d6ffContent-TypeTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffaudio/oggTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffContent-DispositionTa5d6ff"Tb4b4b4: Ta5d6fffTa5d6ff'Ta5d6ffattachment; filename=Ta5d6ff"Tffd700{Te6edf3safe_nameTffd700}Ta5d6ff"Ta5d6ff'Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)

Tf0883e@routesTff7b72.Td2a8ffpostTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/notification-sounds/uploadTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8ffnotification_sound_uploadTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Tff7b72if Tff7b72not Te6edf3appTff7b72.Td2a8ffnotification_sound_managerTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffNotification sound manager unavailableTa5d6ff"Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff503Tb4b4b4,
Tb4b4b4)
Tff7b72tryTb4b4b4:
Te6edf3reader Tff7b72= Tff7b72await Te6edf3requestTff7b72.Td2a8ffmultipartTb4b4b4(Tb4b4b4)
Te6edf3field Tff7b72= Tff7b72await Te6edf3first_multipart_file_fieldTb4b4b4(Te6edf3readerTb4b4b4)
Tff7b72if Te6edf3field Tff7b72is Tff7b72NoneTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffFile field requiredTa5d6ff"Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff400Tb4b4b4,
Tb4b4b4)

Te6edf3filename Tff7b72= Te6edf3fieldTff7b72.Td2a8fffilename Tff7b72or Ta5d6ff"Ta5d6ffuploadTa5d6ff"
Te6edf3extension Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffsplitextTb4b4b4(Te6edf3filenameTb4b4b4)Tb4b4b4[T79c0ff1Tb4b4b4]Tff7b72.Td2a8fflowerTb4b4b4(Tb4b4b4)
Tff7b72if Te6edf3extension Tff7b72not Tff7b72in Tb4b4b4[Ta5d6ff"Ta5d6ff.mp3Ta5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff.oggTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff.wavTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff.m4aTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff.flacTa5d6ff"Tb4b4b4]Tb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6fffTa5d6ff"Ta5d6ffUnsupported file type: Tffd700{Te6edf3extensionTffd700}Ta5d6ff"Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff400Tb4b4b4,
Tb4b4b4)

Tff7b72with Te6edf3tempfileTff7b72.Td2a8ffNamedTemporaryFileTb4b4b4(Te6edf3suffixTff7b72=Te6edf3extensionTb4b4b4, Te6edf3deleteTff7b72=Tff7b72FalseTb4b4b4) Tff7b72as Te6edf3fTb4b4b4:
Te6edf3temp_path Tff7b72= Te6edf3fTff7b72.Td2a8ffname
Tff7b72while Tff7b72TrueTb4b4b4:
Te6edf3chunk Tff7b72= Tff7b72await Te6edf3fieldTff7b72.Td2a8ffread_chunkTb4b4b4(Tb4b4b4)
Tff7b72if Tff7b72not Te6edf3chunkTb4b4b4:
Tff7b72break
Te6edf3fTff7b72.Td2a8ffwriteTb4b4b4(Te6edf3chunkTb4b4b4)

Tff7b72tryTb4b4b4:
Te6edf3storage_filename Tff7b72= Tff7b72await Te6edf3asyncioTff7b72.Td2a8ffto_threadTb4b4b4(
Te6edf3appTff7b72.Td2a8ffnotification_sound_managerTff7b72.Td2a8ffconvert_to_ringtoneTb4b4b4,
Te6edf3temp_pathTb4b4b4,
Tb4b4b4)

Te6edf3sound_id Tff7b72= Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8ffnotification_soundsTff7b72.Td2a8ffaddTb4b4b4(
Te6edf3filenameTff7b72=Te6edf3filenameTb4b4b4,
Te6edf3storage_filenameTff7b72=Te6edf3storage_filenameTb4b4b4,
Tb4b4b4)

Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffNotification sound uploaded and convertedTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffidTa5d6ff"Tb4b4b4: Te6edf3sound_idTb4b4b4,
Ta5d6ff"Ta5d6fffilenameTa5d6ff"Tb4b4b4: Te6edf3filenameTb4b4b4,
Ta5d6ff"Ta5d6ffstorage_filenameTa5d6ff"Tb4b4b4: Te6edf3storage_filenameTb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tff7b72finallyTb4b4b4:
Tff7b72if Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Te6edf3temp_pathTb4b4b4)Tb4b4b4:
Te6edf3osTff7b72.Td2a8ffremoveTb4b4b4(Te6edf3temp_pathTb4b4b4)

Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4}Tb4b4b4, Te6edf3statusTff7b72=T79c0ff500Tb4b4b4)

Tf0883e@routesTff7b72.Td2a8ffpatchTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/notification-sounds/Tffd700{id}Ta5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8ffnotification_sound_patchTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3sound_id Tff7b72= Tffa657intTb4b4b4(Te6edf3requestTff7b72.Td2a8ffmatch_infoTb4b4b4[Ta5d6ff"Ta5d6ffidTa5d6ff"Tb4b4b4]Tb4b4b4)
Te6edf3data Tff7b72= Tff7b72await Te6edf3requestTff7b72.Td2a8ffjsonTb4b4b4(Tb4b4b4)

Te6edf3display_name Tff7b72= Te6edf3dataTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffdisplay_nameTa5d6ff"Tb4b4b4)
Te6edf3is_primary Tff7b72= T79c0ff1 Tff7b72if Te6edf3dataTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffis_primaryTa5d6ff"Tb4b4b4) Tff7b72else Tff7b72None

Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8ffnotification_soundsTff7b72.Td2a8ffupdateTb4b4b4(
Te6edf3sound_idTb4b4b4,
Te6edf3display_nameTff7b72=Te6edf3display_nameTb4b4b4,
Te6edf3is_primaryTff7b72=Te6edf3is_primaryTb4b4b4,
Tb4b4b4)

Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffNotification sound updatedTa5d6ff"Tb4b4b4}Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4}Tb4b4b4, Te6edf3statusTff7b72=T79c0ff500Tb4b4b4)

Tf0883e@routesTff7b72.Td2a8ffdeleteTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/notification-sounds/Tffd700{id}Ta5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8ffnotification_sound_deleteTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3sound_id Tff7b72= Tffa657intTb4b4b4(Te6edf3requestTff7b72.Td2a8ffmatch_infoTb4b4b4[Ta5d6ff"Ta5d6ffidTa5d6ff"Tb4b4b4]Tb4b4b4)
Te6edf3sound Tff7b72= Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8ffnotification_soundsTff7b72.Td2a8ffget_by_idTb4b4b4(Te6edf3sound_idTb4b4b4)
Tff7b72if Te6edf3soundTb4b4b4:
Tff7b72if Te6edf3appTff7b72.Td2a8ffnotification_sound_managerTb4b4b4:
Te6edf3appTff7b72.Td2a8ffnotification_sound_managerTff7b72.Td2a8ffremove_ringtoneTb4b4b4(
Te6edf3soundTb4b4b4[Ta5d6ff"Ta5d6ffstorage_filenameTa5d6ff"Tb4b4b4]Tb4b4b4,
Tb4b4b4)
Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8ffnotification_soundsTff7b72.Td2a8ffdeleteTb4b4b4(Te6edf3sound_idTb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffNotification sound deletedTa5d6ff"Tb4b4b4}Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4}Tb4b4b4, Te6edf3statusTff7b72=T79c0ff500Tb4b4b4)

T8b949e# contacts routes


──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────